When we write queries in TSQL selecting the top ‘n’ number of rows is easy. It can be achieved by a query similar to the following.
SELECT TOP(10) Names FROM [Users] WHERE IsActive = 'True' ORDER BY ApprovedOn DESC
But when selecting the items which are from different tables and with subcategories this is quite tricky.
I had a scenario where Users can comment on each service/product. Each service/product is listed under a sub category. The need is the query should list down the recent 5 comments under each service sub category with the details of who made the comment.
Apparently I have to JOIN 4 tables. Selecting the TOP(n) from each category is challenging. I searched the Internet and some solutions say that execute the queries to get the top 5 in each category and combine them using the UNION. That doesn’t sound good and in my scenario the number of categories is dynamic. (So If I have to go with the above solution I have to write COUNT for sub categories and then follow that with bulky TSQL stored procedure).
This is a method I tried by combining some techniques mentioned in the Internet.
Table Structure (Tables contain more fields, but in the picture only the related fields are shown)
There two ways you can write the query. First using a temporary table which is not advisable in terms of efficiency. Second is using sub queries.
Using Temporary tables.
DECLARE @Temp TABLE ( Row INT, RealServiceID BIGINT, CategoryName VARCHAR(100), ServiceName VARCHAR(100), Comment VARCHAR(MAX), Username VARCHAR(50) ) INSERT INTO @Temp SELECT ROW_NUMBER() OVER (PARTITION BY SC.CategoryID ORDER BY SC.CategoryName) AS Row, RS.RealServiceID, SC.CategoryName, RS.ServiceName, CM.Comment, US.Username FROM RealServices AS RS JOIN Comments AS CM ON RS.RealServiceID = CM.CommentOn JOIN ServiceCategory AS SC ON RS.CategoryID = SC.CategoryID JOIN Users AS US ON CM.UserID = US.UserID ORDER BY SC.CategoryName, CM.CommentOn SELECT * FROM @Temp WHERE Row <= 5
Using Sub queries
SELECT RowNumber, RealServiceID, CategoryID, CategoryName, ServiceName, Comment, Username, SubmissionDate FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY SC.CategoryID ORDER BY SC.CategoryName, CM.CommentOn) AS RowNumber, RS.RealServiceID, SC.CategoryID, SC.CategoryName, RS.ServiceName, CM.Comment, US.Username, CM.SubmissionDate FROM RealServices AS RS JOIN Comments AS CM ON RS.RealServiceID = CM.CommentOn JOIN ServiceCategory AS SC ON RS.CategoryID = SC.CategoryID JOIN Users AS US ON CM.UserID = US.UserID ) AS InnerTable WHERE RowNumber <= 5 ORDER BY ServiceName, SubmissionDate DESC
Feel free to make comments on this