
If you’ve ever needed to rank rows in SQL queries while ensuring no gaps in ranking numbers, then DENSE_RANK() is your friend. This analytical function is incredibly useful when you need to assign rankings based on specific sorting criteria, and unlike RANK(), it avoids skipping numbers when there are duplicates.
Understanding DENSE_RANK in SQL
The DENSE_RANK() function assigns a ranking to each row within a result set based on a specified column order. The key feature of this function is that it does not skip numbers when duplicate values exist.
Its syntax looks like this:
DENSE_RANK() OVER (
PARTITION BY column_name
ORDER BY column_name
)
Here’s how it works:
- PARTITION BY: Divides the data into partitions (optional).
- ORDER BY: Specifies the sorting order used for ranking.
DENSE_RANK vs RANK vs ROW_NUMBER
To understand DENSE_RANK() better, let’s compare it with RANK() and ROW_NUMBER() using the following dataset.
CREATE TABLE Sales (
ID INT PRIMARY KEY,
Employee VARCHAR(50),
Revenue INT
);
INSERT INTO Sales (ID, Employee, Revenue) VALUES
(1, 'Alice', 5000),
(2, 'Bob', 4000),
(3, 'Charlie', 5000),
(4, 'David', 3000),
(5, 'Eve', 3000);
Now, let’s apply all three functions:
SELECT
Employee, Revenue,
RANK() OVER (ORDER BY Revenue DESC) AS rank_value,
DENSE_RANK() OVER (ORDER BY Revenue DESC) AS dense_rank_value,
ROW_NUMBER() OVER (ORDER BY Revenue DESC) AS row_number_value
FROM Sales;
The result set would look like this:
| Employee | Revenue | RANK() | DENSE_RANK() | ROW_NUMBER() |
|---|---|---|---|---|
| Alice | 5000 | 1 | 1 | 1 |
| Charlie | 5000 | 1 | 1 | 2 |
| Bob | 4000 | 3 | 2 | 3 |
| David | 3000 | 4 | 3 | 4 |
| Eve | 3000 | 4 | 3 | 5 |
Key observations:
RANK()skips numbers when duplicates appear (notice the jump from 1 to 3 and 3 to 4).DENSE_RANK()does not skip numbers, keeping rankings compact.ROW_NUMBER()assigns unique row numbers without considering duplicate values.
Practical Use Cases of DENSE_RANK
Finding Top N Records within Groups
Say we have sales data grouped by departments, and we want to get the top 2 employees in each department based on revenue.
SELECT *
FROM (
SELECT Employee, Department, Revenue,
DENSE_RANK() OVER (PARTITION BY Department ORDER BY Revenue DESC) AS ranking
FROM Sales
) ranked
WHERE ranking <= 2;
Removing Duplicate Rankings
If your dataset contains duplicate values in a ranking field and you need a compact ranking list, DENSE_RANK() ensures the numbers are continuous instead of skipping.
Conclusion
DENSE_RANK() is a powerful SQL function when working with ranking data where you need dense, gap-free ranking values. Unlike RANK(), it does not skip numbers when duplicates exist, making it particularly useful for leaderboard statistics, sales analysis, and top-N reporting.
Understanding when to use DENSE_RANK() versus RANK() and ROW_NUMBER() can significantly improve how you structure your queries and manage result sets. Hopefully, the examples provided give you a clear insight into how it works in practice!
Other interesting article:
How RANK works in SQL? Best RANK examples