Learnitweb

DENSE_RANK() Function

The DENSE_RANK() function is an analytic (window) function in Oracle SQL that assigns ranks to rows in an ordered set without gaps in ranking values, even when there are ties.

It is especially useful when you want to generate rankings with continuous numbers, even for rows with duplicate values.

1. Syntax

DENSE_RANK() OVER (
    [PARTITION BY partition_expression]
    ORDER BY order_expression [ASC|DESC]
)

Parameters:

  • PARTITION BY (optional): Divides the data into groups. Ranking restarts within each group.
  • ORDER BY: Defines how rows are ranked.
  • ASC or DESC: Rank in ascending or descending order.

2. Key Features

  • Ties (equal values) receive the same rank.
  • No gaps in ranks (unlike RANK()).
  • Always starts from 1.
  • Works as a non-aggregating analytic function: It does not remove rows or change result size.

3. Example Table: employees

CREATE TABLE employees (
  employee_id NUMBER,
  name VARCHAR2(50),
  department_id NUMBER,
  salary NUMBER
);

INSERT INTO employees VALUES (1, 'Alice', 10, 5000);
INSERT INTO employees VALUES (2, 'Bob', 10, 7000);
INSERT INTO employees VALUES (3, 'Charlie', 20, 6000);
INSERT INTO employees VALUES (4, 'David', 20, 6000);
INSERT INTO employees VALUES (5, 'Eve', 10, 7000);
COMMIT;

4. Basic Usage: Ranking by Salary

SELECT name, salary,
       DENSE_RANK() OVER (ORDER BY salary DESC) AS rank
FROM employees;

Output:

NAMESALARYRANK
Bob70001
Eve70001
Charlie60002
David60002
Alice50003

Explanation:

  • Bob and Eve have the highest salary, so both get rank 1.
  • Charlie and David share rank 2.
  • Alice gets rank 3.
  • No gaps in rank numbers (no missing 2 between 1 and 3).

5. DENSE_RANK with PARTITION BY

Let’s say you want to rank employees within each department.

SELECT department_id, name, salary,
       DENSE_RANK() OVER (
           PARTITION BY department_id
           ORDER BY salary DESC
       ) AS dept_rank
FROM employees;

Output:

DEPARTMENT_IDNAMESALARYDEPT_RANK
10Bob70001
10Eve70001
10Alice50002
20Charlie60001
20David60001

Explanation:

  • Ranking restarts in each department.
  • Duplicate salaries within a department get the same rank.

6. DENSE_RANK vs RANK vs ROW_NUMBER

FunctionDuplicates Get Same RankSkips RanksContinuous RanksUse Case
RANK()YesYesNoLeaderboards with ties
DENSE_RANK()YesNoYesOrdered ranks with no gaps
ROW_NUMBER()NoNoYesUnique row IDs (no duplicates)

Example with all three:

SELECT name, salary,
       RANK() OVER (ORDER BY salary DESC) AS rank,
       DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank,
       ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees;

Output:

NAMESALARYRANKDENSE_RANKROW_NUM
Bob7000111
Eve7000112
Charlie6000323
David6000324
Alice5000535

7. Real-World Use Case: Top 2 Salaries per Department

SELECT *
FROM (
  SELECT department_id, name, salary,
         DENSE_RANK() OVER (
             PARTITION BY department_id
             ORDER BY salary DESC
         ) AS rnk
  FROM employees
)
WHERE rnk <= 2;

Output:

DEPARTMENT_IDNAMESALARYRNK
10Bob70001
10Eve70001
10Alice50002
20Charlie60001
20David60001

8. Notes and Best Practices

  • DENSE_RANK() is best used when you want consecutive ranks without gaps.
  • Works well for leaderboards, prize allocations, or filtering top-N records per group.
  • Always combine with ORDER BY inside OVER() clause.
  • Use PARTITION BY to restart ranking for groups (e.g., departments, categories).

9. Summary

FeatureValue
Function TypeAnalytic (Window)
Handles TiesYes
Rank SkippingNo (ranks are dense)
Default Start Rank1
PartitioningOptional, for group-wise ranking

10. Conclusion

The DENSE_RANK() function in Oracle SQL is a powerful analytic function when:

  • You need ranked output with no gaps.
  • You want to find top-N rows per group.
  • You are working with sorted data with duplicates and want fair ranking.

It’s a must-know tool for data analysis, reporting, and real-time ranking logic in Oracle SQL.