Skip to content
Laviyx Learn

Try

SQL course menu

SQL DENSE_RANK(): Rank Without Gaps (Nth Highest Value)

Learn SQL DENSE_RANK(): rank rows with ties and no gaps, find the Nth highest value (the classic second-highest salary question), get top-N distinct values per group, and compare with RANK.

Advanced6 min readUpdated
On this page

DENSE_RANK() ranks rows like RANK: tied values share a rank. The difference is that DENSE_RANK never leaves gaps. After two rows tie for 1st, the next row is 2nd, not 3rd. In other words, it counts distinct values.

The example table#

scores (Maths)

studentscore
Asha92
Ravi85
Meera92
John78
Priya85

Syntax#

SQL
DENSE_RANK() OVER (
  [PARTITION BY column]
  ORDER BY column
)

Dense ranking#

SQLRun
SELECT student, score,
       DENSE_RANK() OVER (ORDER BY score DESC) AS dense
FROM scores
WHERE subject = 'Maths'
ORDER BY dense, student;
Output
student | score | dense
--------+-------+------
Asha    | 92    | 1
Meera   | 92    | 1
Priya   | 85    | 2
Ravi    | 85    | 2
John    | 78    | 3

There are three distinct scores (92, 85, 78), so the ranks are 1, 2 and 3. With RANK, John would be 5th.

ScoreRANKDENSE_RANK
9211
9211
8532
8532
7853

The Nth highest value#

"Find the second-highest score" is a classic interview question, and DENSE_RANK handles ties correctly:

SQLRun
SELECT DISTINCT score
FROM (
  SELECT score,
         DENSE_RANK() OVER (ORDER BY score DESC) AS d
  FROM scores
  WHERE subject = 'Maths'
) t
WHERE d = 2;
Output
score
-----
85

Compare the alternatives:

  • ORDER BY score DESC LIMIT 1 OFFSET 1 returns 92 (Meera's tied score), which is wrong.
  • ROW_NUMBER() ... = 2 also lands on the second 92.
  • RANK() ... = 2 returns nothing, because no row has rank 2.

Only DENSE_RANK treats "second highest" as "second highest distinct value". Change d = 2 to d = N for any N.

Top N distinct values per group#

The top two distinct scores in each subject, including everyone who achieved them:

SQLRun
SELECT subject, student, score
FROM (
  SELECT subject, student, score,
         DENSE_RANK() OVER (PARTITION BY subject ORDER BY score DESC) AS d
  FROM scores
) t
WHERE d <= 2
ORDER BY subject, score DESC, student;
Output
subject | student | score
--------+---------+------
Maths   | Asha    | 92
Maths   | Meera   | 92
Maths   | Priya   | 85
Maths   | Ravi    | 85
Science | Ravi    | 95
Science | Asha    | 88
Science | John    | 88

Which ranking function should I use?#

QuestionUse
Exactly one row per position (pagination, de-duplication)ROW_NUMBER
Positions like a race, where ties push others downRANK
Nth highest value; levels or tiersDENSE_RANK

Common mistakes#

Practice#

Practice exercise

Find the employee(s) with the second-highest salary in each department, using DENSE_RANK.

Show hint

Partition by department, order by salary descending, and keep d = 2 in an outer query.

Show solution
SQLRun
SELECT name, department, salary
FROM (
  SELECT name, department, salary,
         DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS d
  FROM employees
) t
WHERE d = 2;
Output
name | department  | salary
-----+-------------+-------
Ravi | Engineering | 78000
Asha | Sales       | 52000

If two Engineering employees had tied for the top salary, DENSE_RANK would still correctly return the next distinct salary.

Key takeaway#

Finished this lesson?