How to Get Top N Records Per Group? – Ranking Function – Interview Question of the Week #156

Question: How do you return the top two students in each class, ranked by marks?

Answer: Use ROW_NUMBER() partitioned by class, then keep row numbers 1 and 2. I gave this puzzle to more than 40 interview candidates. It is a small problem with one important word: each. A single TOP (2) gives two students for the whole table, while the question asks for two students in Science, two in Maths, and two in Art.

Each of three trays displays its two tallest stones ahead of shorter stones

Here is the original nine-student example, moved into a temporary table so it can be tried without leaving a permanent StudentClass table behind. The names, classes, and marks are the same as in the interview puzzle.

CREATE TABLE #StudentClass
(
    ID int NOT NULL PRIMARY KEY,
    StudentName varchar(100) NOT NULL,
    ClassName varchar(100) NOT NULL,
    Marks int NOT NULL
);

INSERT INTO #StudentClass (ID, StudentName, ClassName, Marks)
VALUES (1, 'Roger',  'Science', 50),
       (2, 'Sara',   'Science', 40),
       (3, 'Jimmy',  'Science', 30),
       (4, 'Mike',   'Maths',   50),
       (5, 'Mona',   'Maths',   30),
       (6, 'Ronnie', 'Maths',   10),
       (7, 'James',  'Art',     50),
       (8, 'Mona',   'Art',     35),
       (9, 'Roger',  'Art',     25);

Partition the ranking by ClassName, then sort marks descending inside each partition. I added ID as a tie-breaker so an equal mark still produces a repeatable order when the rule is “exactly two rows.”

WITH Ranked AS
(
    SELECT ID, StudentName, ClassName, Marks,
           ROW_NUMBER() OVER
           (PARTITION BY ClassName ORDER BY Marks DESC, ID ASC)
               AS StRank
    FROM #StudentClass
)
SELECT StRank, ID, StudentName, ClassName, Marks
FROM Ranked
WHERE StRank <= 2
ORDER BY ClassName, StRank;

The result shows exactly two ranked rows for each of the three classes.

Original SQL Server result showing two ranked students for Art, Maths, and Science
Original result: the top two students within each class.

If the business rule is “include everyone tied for second,” ROW_NUMBER() is the wrong ranking rule: it always assigns separate row numbers. Consider RANK() or DENSE_RANK() and decide whether gaps after ties are acceptable.

For more ranking practice, see my earlier examples on RANK, DENSE_RANK and ROW_NUMBER, a broader ranking-functions example, and finding the Nth-highest row. For related variations, see PERCENT_RANK and returning top and bottom rows together. The interview answer starts by separating “top overall” from “top within each group.”

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

Ranking Functions, SQL Function, SQL Scripts, SQL Server
Previous Post
How to List All the Nonclustered Indexes of Your Table? – Interview Question of the Week #155
Next Post
How to Find DISTINCT COUNT of Column Rows Without Using Distinct Count Keywords? – Interview Question of the Week #157

Related Posts

3 Comments. Leave new

  • In. MySQL do we have ranking functionality. Pls give example.. I am asking all functionality in ranking

    Reply
  • What about this?

    SELECT * FROM #StudentClass AS A
    WHERE A.Marks IN (SELECT TOP 2 Marks FROM #StudentClass AS X WHERE X.ClassName = A.ClassName ORDER BY x.Marks DESC)

    Reply
  • Hi Pinal,

    I would prefer to use DENSE_RANK() over ROW_NUMBER(), as we might have more than one student in the class with same marks.

    Thanks,
    Srini

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.