What is the difference between ROW_NUMBER, RANK and DENSE_RANK?
They differ only in how they treat ties, and the difference is entirely about what happens after a group of equal values.
CREATE TABLE scores (
id INTEGER PRIMARY KEY,
student_id INTEGER NOT NULL,
score INTEGER NOT NULL
);
INSERT INTO scores (id, student_id, score) VALUES
(1, 1, 90),
(2, 1, 90),
(3, 1, 70),
(4, 2, 85);
SELECT student_id,
score,
ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY score DESC) AS row_num,
RANK() OVER (PARTITION BY student_id ORDER BY score DESC) AS rnk,
DENSE_RANK() OVER (PARTITION BY student_id ORDER BY score DESC) AS dense_rnk
FROM scores
ORDER BY student_id, row_num;Student 1's two scores of 90 get row numbers 1 and 2, ranks 1 and 1, and dense ranks 1 and 1. The score of 70 gets row number 3, rank 3 and dense rank 2. Student 2's single score of 85 gets 1, 1 and 1.
So: ROW_NUMBER always produces a distinct sequential number, breaking ties arbitrarily — which means it is not reproducible unless you add a tiebreaker to the ORDER BY. RANK assigns the same rank to tied rows and then skips the next ranks, so with two rows at rank 1 the next rank is 3. DENSE_RANK assigns the same rank to tied rows and does not skip, so the next rank after two rows at rank 1 is 2.
The practical consequence is what happens when you filter on the ranking. WHERE rnk <= 3 with RANK can return more than three rows per group, because a tie at rank 3 means four rows qualify. WHERE dense_rnk <= 3 returns exactly the top three distinct score values, however many rows share them. And WHERE row_num <= 3 returns exactly three rows, but which three is arbitrary when there is a tie.