Difference between Rank and Dense Rank in SQL
By Mukesh Kumar
Updated on Apr 28, 2025 | 5 min read | 1.6k views
Share:
For working professionals
For fresh graduates
More
By Mukesh Kumar
Updated on Apr 28, 2025 | 5 min read | 1.6k views
Share:
Table of Contents
Why does one query return a gap in ranking while another doesn’t—despite using almost identical SQL functions?
This confusion often arises when comparing RANK() and DENSE_RANK()—two powerful window functions used in SQL for assigning rankings within partitions.
RANK() assigns the same rank to tied values but skips the next rank(s), causing gaps. On the other hand, DENSE_RANK() also assigns the same rank to ties but continues with the next immediate rank—no gaps.
The key difference lies in how they handle ranking positions for duplicate values.
In this blog, we’ll demystify the differences between RANK and DENSE RANKusing real-world examples, practical SQL syntax, performance tips, and use cases to help you decide which one to use and when.
Overcome the challenges of NoSQL with a strong foundation in data science and machine learning. Explore our Data Science and Machine Learning Courses to master database management and advanced data techniques today!
RANK() is a window function in SQL used to assign a unique rank to rows within a result set based on the specified order of values. It is typically used with the OVER() clause and ORDER BY to generate rankings within partitions.
However, if two or more rows have the same value, RANK() assigns them the same rank—but skips the next rank(s), creating gaps.
Take your data science skills to the next level with these top courses:
SELECT column1, column2,
RANK() OVER (PARTITION BY columnX ORDER BY columnY DESC) AS rank
FROM your_table;
Example:
Consider a sales table:
Employee |
Revenue |
Alice | 1000 |
Bob | 900 |
Charlie | 900 |
Dave | 800 |
Using RANK() on Revenue:
Employee |
Revenue |
Rank |
Alice | 1000 | 1 |
Bob | 900 | 2 |
Charlie | 900 | 2 |
Dave | 800 | 4 |
Note: Rank 3 is skipped due to tie.
Use Cases:
Also Read:
DENSE_RANK() is a window function in SQL that assigns ranks to rows based on a specified order—but unlike RANK(), it does not skip ranks when duplicate values occur. This ensures consecutive ranking even when there are ties.
It’s especially useful when you want no gaps in the ranked output.
SELECT column1, column2,
DENSE_RANK() OVER (PARTITION BY columnX ORDER BY columnY DESC) AS dense_rank
FROM your_table;
Example:
Using the same sales table:
Employee |
Revenue |
Alice | 1000 |
Bob | 900 |
Charlie | 900 |
Dave | 800 |
With DENSE_RANK() on Revenue:
Employee |
Revenue |
Dense_Rank |
Alice | 1000 | 1 |
Bob | 900 | 2 |
Charlie | 900 | 2 |
Dave | 800 | 3 |
Note: No skipped ranks—ranks are dense and consecutive.
Must Read:
Key Difference from RANK():
While both functions assign the same rank to tied values, DENSE_RANK() does not leave gaps in the sequence—unlike RANK().
Parameter |
RANK() |
DENSE_RANK() |
Ranking Logic | Assigns the same rank to ties, then skips the next rank(s) | Assigns the same rank to ties, no ranks are skipped |
Gaps in Ranking | Yes – introduces gaps after duplicates | No – ranks remain consecutive even with ties |
Use Case | Best for ranking where position matters (e.g., leaderboard) | Best for reports with strict rank order continuity |
Output Behavior (with Ties) | Ties get same rank, next rank jumps ahead | Ties get same rank, next rank is just one higher |
Syntax | RANK() OVER (PARTITION BY ... ORDER BY ...) | DENSE_RANK() OVER (PARTITION BY ... ORDER BY ...) |
Performance | Nearly identical performance | Nearly identical performance |
First Rank Assigned | Always starts from 1 | Always starts from 1 |
Result Consistency | Varies when there are ties | More consistent in sequential ranking |
Gap Sensitivity | Sensitive to duplicates – causes rank jumps | Ignores gaps caused by duplicates |
Sorting Requirement | Requires ORDER BY in OVER() clause | Requires ORDER BY in OVER() clause |
Standard Compliance | Part of SQL:2003 standard | Part of SQL:2003 standard |
Ideal For | Competitive rankings, top-N with tie handling | Business reports, non-skip rank listings, product/category sorting |
Also Read:
Let’s take a simple dataset called sales_data:
Employee_ID |
Employee_Name |
Revenue |
101 | Alice | 1000 |
102 | Bob | 900 |
103 | Charlie | 900 |
104 | David | 800 |
105 | Eva | 700 |
SELECT Employee_Name, Revenue,
RANK() OVER (ORDER BY Revenue DESC) AS rank_position
FROM sales_data;
Output:
Employee_Name |
Revenue |
rank_position |
Alice | 1000 | 1 |
Bob | 900 | 2 |
Charlie | 900 | 2 |
David | 800 | 4 |
Eva | 700 | 5 |
Note: Rank 3 is skipped due to the tie between Bob and Charlie.
SELECT Employee_Name, Revenue,
DENSE_RANK() OVER (ORDER BY Revenue DESC) AS dense_rank_position
FROM sales_data;
Output:
Employee_Name |
Revenue |
dense_rank_position |
Alice | 1000 | 1 |
Bob | 900 | 2 |
Charlie | 900 | 2 |
David | 800 | 3 |
Eva | 700 | 4 |
Note: No ranks are skipped—ranking remains dense.
Must Read:
Choosing between RANK() and DENSE_RANK() depends on how you want to handle ties in your result set and the business context of your report.
In short, choose RANK() for accuracy with position gaps, and DENSE_RANK() for sequential clarity without gaps.
Must Check:
Even experienced developers can trip up when working with RANK() and DENSE_RANK(). Here are some frequent errors:
Mistake |
Why It Happens |
How to Fix It |
Missing ORDER BY in OVER() clause | Without ORDER BY, ranking logic is undefined | Always specify ORDER BY inside the OVER() clause |
Assuming ranks are unique | Ties result in duplicate ranks | Use ROW_NUMBER() if you need unique values |
Not using PARTITION BY when needed | Ranks calculated over full dataset instead of group | Add PARTITION BY to segment results (e.g., by department) |
Expecting continuous ranking from RANK() | RANK() introduces gaps | Use DENSE_RANK() for continuous ranking |
Wrong column in ORDER BY | Leads to incorrect rank calculations | Double-check sorting logic based on requirement |
Using RANK in WHERE clause directly | Window functions can't be used in WHERE | Use subqueries or CTEs to filter on ranks |
While RANK() and DENSE_RANK() are powerful, their performance can degrade with large datasets if not optimized properly.
Aspect |
Insight |
Optimization Tip |
Execution Time | Both functions use sorting; expensive on large datasets | Create indexes on columns used in ORDER BY |
Memory Usage | Sorting over wide partitions consumes memory | Minimize partition size when possible |
Parallelism | Modern SQL engines parallelize window functions | Use efficient query plans and review EXPLAIN plans |
Indexing | No direct index usage for window functions | But indexes on ORDER BY columns can improve sort performance |
CTE/Subquery Overuse | Over-nesting leads to redundant computation | Materialize intermediate results or use temp tables for reuse |
Filtering Ranked Rows | Filtering ranks requires another layer (CTE or subquery) | Use WITH clause and filter in outer query for clarity and speed |
Both RANK() and DENSE_RANK() are powerful tools for ranking data, but the choice depends on the context of your analysis.
Similar Read: Check our Top Differences Between Blogs
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
231 articles published
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources