Free tutorials & notes in Hindi & English · Clean code examples · Mobile friendly learning
MySQL + SQL · Lesson 81

ROW_NUMBER, RANK and DENSE_RANK

ROW_NUMBER, RANK and DENSE_RANK

FunctionTiesNext value
ROW_NUMBER()Always unique numbersAlways +1
RANK()Peers share rankGap after ties
DENSE_RANK()Peers share rankNo gap
Choose by requirement: fixed row count uses ROW_NUMBER; competition positions use RANK; distinct score bands use DENSE_RANK.

Verified Tie Dataset

The advanced_scores table deliberately gives Meera and Sana the same 92 marks in X-A. That tie exposes the real difference between the three functions.

ClassDescending marks
X-A92 Meera, 92 Sana, 86 Aarav
X-B88 Vihaan, 81 Riya, 74 Kabir

Side-by-Side Ranking Query

SELECT student_name, class_name, marks,
       ROW_NUMBER() OVER (
         PARTITION BY class_name
         ORDER BY marks DESC, student_id
       ) AS row_no,
       RANK() OVER (
         PARTITION BY class_name
         ORDER BY marks DESC
       ) AS rank_no,
       DENSE_RANK() OVER (
         PARTITION BY class_name
         ORDER BY marks DESC
       ) AS dense_rank_no
FROM advanced_scores
ORDER BY class_name, row_no;

ROW_NUMBER adds student_id as a deterministic tie-breaker. RANK and DENSE_RANK order only by marks so equal marks remain peers.

Verified Ranking Output

Meera | X-A | 92 | row 1 | rank 1 | dense 1 Sana | X-A | 92 | row 2 | rank 1 | dense 1 Aarav | X-A | 86 | row 3 | rank 3 | dense 2 Vihaan | X-B | 88 | row 1 | rank 1 | dense 1 Riya | X-B | 81 | row 2 | rank 2 | dense 2 Kabir | X-B | 74 | row 3 | rank 3 | dense 3

RANK skips position 2 in X-A after the two tied leaders; DENSE_RANK assigns Aarav 2. ROW_NUMBER still assigns distinct row positions 1, 2 and 3.

Deterministic Ordering and Tie Policy

A ranking report must state whether equal marks share a position and how fixed-row selections break ties.

  • All tied winners: filter RANK or DENSE_RANK <= N.
  • Exactly N rows: filter ROW_NUMBER <= N using a documented tie-breaker.
  • Do not add a unique key to RANK unless you intentionally want to destroy peer ties.
  • Top-level ORDER BY is still needed for final display order.

Top Two Rows per Class

WITH ranked AS (
  SELECT student_id, student_name,
         class_name, marks,
         ROW_NUMBER() OVER (
           PARTITION BY class_name
           ORDER BY marks DESC, student_id
         ) AS row_no
  FROM advanced_scores
)
SELECT student_name, class_name, marks, row_no
FROM ranked
WHERE row_no <= 2
ORDER BY class_name, row_no;
Meera | X-A | 92 | 1 Sana | X-A | 92 | 2 Vihaan | X-B | 88 | 1 Riya | X-B | 81 | 2

A window value cannot be filtered in WHERE at the same query level, so the CTE calculates it first. Replace ROW_NUMBER with RANK if all ties at the Nth position must be included, even when more than N rows result.

Deduplication and Pagination Patterns

Keep the latest record per student

WITH latest AS (
  SELECT log_id, student_id, event_time,
         ROW_NUMBER() OVER (
           PARTITION BY student_id
           ORDER BY event_time DESC, log_id DESC
         ) AS row_no
  FROM attendance_log
)
SELECT log_id, student_id, event_time
FROM latest
WHERE row_no = 1;

The unique log_id tie-breaker makes “latest” deterministic. Review before deleting older duplicates. For pagination, ROW_NUMBER can label a stable ordered snapshot, but live data changes can shift pages; keyset pagination is often safer for frequently changing applications.

Performance, Mistakes and Practice

  • Partition and ordering may require sorting; inspect EXPLAIN.
  • Project only required columns into the ranking stage.
  • Indexing may help filtering and access, but it does not eliminate every window sort.
  • Never use ROW_NUMBER without deterministic ordering when reproducibility matters.
  • Test ties at first, Nth and last positions.

Practice: return all class winners with RANK; return top two distinct score bands with DENSE_RANK; return exactly two students with ROW_NUMBER; add a tie at X-B second place and compare result counts.

Official References

Syntax and behavior were checked against the official MySQL 8.4 manual. Verify plans and limits on your own server before production use.

Frequently Asked Questions

How does ROW_NUMBER handle ties?
It assigns a unique sequence number to every row. Without a complete deterministic ORDER BY, the order among tied rows is not guaranteed.
How does RANK handle ties?
Peers receive the same rank and the next rank contains a gap. Two rows at rank 1 make the next rank 3.
How does DENSE_RANK handle ties?
Peers share a rank, but the next distinct value receives the next consecutive rank, so no gap appears.
How do I return top N rows per group?
Calculate ROW_NUMBER or an appropriate rank in a CTE/derived table partitioned by the group, then filter the result in the outer query.
Should I add a unique key to RANK ordering?
Only if ties should be broken. Adding student_id to the RANK ORDER BY makes equal marks non-peers and changes tie semantics.
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 Live Code Editor

This page's programs are ready here — run them, edit them, and learn. No installation needed.
Powered by OneCompiler. The code loads into the editor automatically — press Run to see the output. If the editor does not open, open it in a new tab.