Md Mominul Islam | Software and Data Enginnering | SQL Server, .NET, Power BI, Azure Blog

while(!(succeed=try()));

LinkedIn Portfolio Banner

Latest

Home Top Ad

Responsive Ads Here

Post Top Ad

Responsive Ads Here

Tuesday, August 26, 2025

SQL Server RANK vs DENSE_RANK vs ROW_NUMBER: Window Function Guide

 

Introduction to Ranking Functions

SQL Server provides powerful window functions for assigning ranks to rows within a result set partition. RANK, DENSE_RANK, and ROW_NUMBER are essential for sorting, pagination, and top-N per group queries. While they seem similar, their behavior with ties and numbering gaps is critically different.

Core Concepts and Syntax

All three functions follow the same basic syntax but behave differently:

sql
FUNCTION_NAME() OVER (
    [PARTITION BY partition_expression, ... ]
    ORDER BY sort_expression [ASC | DESC], ...
)
  • PARTITION BY: Divides the result set into groups (optional)

  • ORDER BY: Defines the logical order within each partition

1. ROW_NUMBER() Function

Assigns a unique sequential integer to each row within a partition, starting at 1. Never produces ties - even if rows have identical values.

Example Scenario: Numbering employees by salary within each department.

sql
CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    Name VARCHAR(50),
    Department VARCHAR(50),
    Salary DECIMAL(10, 2)
);

INSERT INTO Employees VALUES
(1, 'John', 'Sales', 50000),
(2, 'Jane', 'Sales', 60000),
(3, 'Bob', 'Sales', 60000), -- Same salary as Jane
(4, 'Alice', 'IT', 70000),
(5, 'Charlie', 'IT', 65000);

SELECT 
    Department,
    Name,
    Salary,
    ROW_NUMBER() OVER (PARTITION BY Department ORDER BY Salary DESC) as RowNum
FROM Employees;

Result:

DepartmentNameSalaryRowNum
ITAlice70000.001
ITCharlie65000.002
SalesJane60000.001
SalesBob60000.002
SalesJohn50000.003

Key Point: Even though Jane and Bob have identical salaries (60000), they get different row numbers.

2. RANK() Function

Assigns a unique rank to each distinct row, with the same rank for tied values, leaving gaps in the sequence.

Example: Ranking employees by salary across all departments.

sql
SELECT 
    Department,
    Name,
    Salary,
    RANK() OVER (ORDER BY Salary DESC) as Rank
FROM Employees;

Result:

DepartmentNameSalaryRank
ITAlice70000.001
ITCharlie65000.002
SalesJane60000.003
SalesBob60000.003-- Tie: same rank
SalesJohn50000.005-- Gap: rank 4 is skipped

Key Point: Jane and Bob are tied for rank 3, so the next rank (John) becomes 5, not 4.

3. DENSE_RANK() Function

Assigns a unique rank to each distinct row, with the same rank for tied values, but without gaps in the ranking sequence.

Example: Dense ranking by salary.

sql
SELECT 
    Department,
    Name,
    Salary,
    DENSE_RANK() OVER (ORDER BY Salary DESC) as DenseRank
FROM Employees;

Result:

DepartmentNameSalaryDenseRank
ITAlice70000.001
ITCharlie65000.002
SalesJane60000.003
SalesBob60000.003-- Tie: same rank
SalesJohn50000.004-- No gap: continues to 4

Key Point: The ranking continues sequentially without gaps after ties.

Comparative Analysis

FunctionTies HandlingGapsSequenceUse Cases
ROW_NUMBERNever - unique numbersNo gapsContinuousPagination, removing duplicates, top-N per group
RANKSame rank for tiesGaps after tiesNon-continuousCompetition rankings, academic grading
DENSE_RANKSame rank for tiesNo gapsContinuousStatistical analysis, percentile calculations

Performance Considerations

  1. Indexing: Proper indexes on PARTITION BY and ORDER BY columns significantly improve performance

  2. Large Datasets: ROW_NUMBER() is generally fastest, while RANK() and DENSE_RANK() may have overhead due to tie handling

  3. Memory Usage: Window functions can be memory-intensive on large partitions

Advanced Example: Top 2 Earners Per Department

sql
WITH RankedEmployees AS (
    SELECT 
        Department,
        Name,
        Salary,
        DENSE_RANK() OVER (PARTITION BY Department ORDER BY Salary DESC) as RankValue
    FROM Employees
)
SELECT Department, Name, Salary, RankValue
FROM RankedEmployees
WHERE RankValue <= 2;

Result:

DepartmentNameSalaryRankValue
ITAlice70000.001
ITCharlie65000.002
SalesJane60000.001
SalesBob60000.001-- Both top earners in Sales

Best Practices

  1. Use ROW_NUMBER() for unique sequencing and pagination

  2. Use RANK() when you need to maintain ranking gaps (e.g., Olympic medals)

  3. Use DENSE_RANK() for continuous ranking without gaps

  4. Always specify ORDER BY - it's mandatory for ranking functions

  5. Use PARTITION BY for grouping within window functions

  6. Consider indexing on columns used in PARTITION BY and ORDER BY clauses

Common Pitfalls

  1. Missing ORDER BY: Will cause syntax error

  2. Forgetting PARTITION BY: May produce unexpected results across groups

  3. Assuming order: Without explicit ORDER BY, the order is not guaranteed

  4. Performance issues: Poorly designed window functions can be slow on large datasets

Conclusion

Understanding the differences between RANK, DENSE_RANK, and ROW_NUMBER is crucial for effective data analysis in SQL Server. ROW_NUMBER provides unique sequencing, RANK allows for ties with gaps, and DENSE_RANK provides continuous ranking without gaps. Choose the appropriate function based on your specific use case, considering both the desired output and performance implications. These window functions are powerful tools for complex sorting, ranking, and pagination requirements in modern database applications.

No comments:

Post a Comment

Thanks for your valuable comment...........
Md. Mominul Islam

Post Bottom Ad

Responsive Ads Here