Summary: in this tutorial, you’ll learn how to use the SQL DENSE_RANK()
function to rank rows in partitions without gaps in ranking values.
Introduction to SQL DENSE_RANK() function #
The DENSE_RANK()
is a window function that assigns a rank to each row in partitions with no gaps in the ranking values.
If two or more rows in the same partition have the same values, they receive the same rank. The next row has the rank incremented by one.
Unlike the RANK()
function, the DENSE_RANK()
function always generates consecutive rank values.
Here’s the syntax of the DENSE_RANK()
window function:
DENSE_RANK() OVER (
PARTITION BY expression1 [{,expression2...}]
ORDER BY expression1 [ASC|DESC], [{,expression2...}]
)
Code language: SQL (Structured Query Language) (sql)
In this syntax:
- The
PARTITION BY
clause divides the result set into partitions. - The
ORDER BY
specifies the order of rows in each partition. - The
DENSE_RANK(
) function is applied to the rows in the specified order of each partition. It resets the rank value when the partition boundary is crossed.
Basic DENSE_RANK function example #
First, create a new table dense_rank_demos
with one column v
:
CREATE TABLE IF NOT EXISTS dense_rank_demos (v VARCHAR);
Code language: SQL (Structured Query Language) (sql)
Second, insert some rows into the dense_rank_demos
table:
INSERT INTO
dense_rank_demos (v)
VALUES
('A'),
('B'),
('B'),
('C'),
('D'),
('D'),
('E');
Code language: SQL (Structured Query Language) (sql)
Third, retrieve data from the dense_rank_demos
table:
SELECT v FROM dense_rank_demos;
Code language: SQL (Structured Query Language) (sql)
Output:
v
---
A
B
B
C
D
D
E
Code language: SQL (Structured Query Language) (sql)
Finally, use the DENSE_RANK()
and RANK()
functions to assign ranks to each row of the result set:
SELECT
v,
DENSE_RANK() OVER ( ORDER BY v) my_dense_rank,
RANK() OVER (ORDER BY v) my_rank
FROM
dense_rank_demos;
Code language: SQL (Structured Query Language) (sql)
Output:
v | my_dense_rank | my_rank
---+---------------+---------
A | 1 | 1
B | 2 | 2
B | 2 | 2
C | 3 | 4
D | 4 | 5
D | 4 | 5
E | 5 | 7
Code language: SQL (Structured Query Language) (sql)
Using SQL DENSE_RANK() over the result set example #
We’ll use the employees
and departments
tables from the sample database for the demonstration purposes:
The following statement uses the DENSE_RANK()
function to rank employees by their salaries:
SELECT
first_name,
last_name,
salary,
DENSE_RANK() OVER (
ORDER BY salary DESC
) salary_rank
FROM
employees;
Code language: SQL (Structured Query Language) (sql)
Output:
first_name | last_name | salary | salary_rank
-------------+-------------+----------+-------------
Steven | King | 24000.00 | 1
Neena | Kochhar | 17000.00 | 2
Lex | De Haan | 17000.00 | 2
John | Russell | 14000.00 | 3
Karen | Partners | 13500.00 | 4
Michael | Hartstein | 13000.00 | 5
Shelley | Higgins | 12000.00 | 6
Nancy | Greenberg | 12000.00 | 6
Den | Raphaely | 11000.00 | 7
...
Code language: SQL (Structured Query Language) (sql)
In this example, the DENSE_RANK()
function treats the whole result set as a single partition because we don’t use the PARTITION BY
clause.
The ORDER BY
clause sorts employee salaries from high to low and the DENSE_RANK()
function assigns a rank to each employee based on the salary amount.
Using SQL DENSE_RANK() function over partition example #
The following statement uses the DENSE_RANK
function to rank employees in each department by their salaries:
SELECT
first_name,
last_name,
department_name,
salary,
DENSE_RANK() OVER (
PARTITION BY department_name
ORDER BY salary DESC
) salary_rank
FROM
employees e
INNER JOIN departments d ON d.department_id = e.department_id;
Code language: SQL (Structured Query Language) (sql)
Output:
first_name | last_name | department_name | salary | salary_rank
-------------+-------------+------------------+----------+-------------
Shelley | Higgins | Accounting | 12000.00 | 1
William | Gietz | Accounting | 8300.00 | 2
Jennifer | Whalen | Administration | 4400.00 | 1
Steven | King | Executive | 24000.00 | 1
Neena | Kochhar | Executive | 17000.00 | 2
Lex | De Haan | Executive | 17000.00 | 2
Nancy | Greenberg | Finance | 12000.00 | 1
Daniel | Faviet | Finance | 9000.00 | 2
John | Chen | Finance | 8200.00 | 3
Jose Manuel | Urman | Finance | 7800.00 | 4
Ismael | Sciarra | Finance | 7700.00 | 5
Luis | Popp | Finance | 6900.00 | 6
...
Code language: SQL (Structured Query Language) (sql)
In this example:
- First, the
PARTITION BY
clause divides the employees by departments into partitions. - Then, the
ORDER BY
clause sorts the employees in each department (partition) by their salaries. - Third, the
DENSE_RANK()
function assigns a rank to each row in each partition based on salary order.
If you want to find only employees who have the highest salary in their departments, you can use a subquery in the FROM
clause as follows:
SELECT
*
FROM
(
SELECT
first_name,
last_name,
department_name,
salary,
DENSE_RANK() OVER (
PARTITION BY
department_name
ORDER BY
salary DESC
) salary_rank
FROM
employees e
INNER JOIN departments d ON d.department_id = e.department_id
) t
WHERE
salary_rank = 1;
Code language: SQL (Structured Query Language) (sql)
Output:
first_name | last_name | department_name | salary | salary_rank
------------+-----------+------------------+----------+-------------
Shelley | Higgins | Accounting | 12000.00 | 1
Jennifer | Whalen | Administration | 4400.00 | 1
Steven | King | Executive | 24000.00 | 1
Nancy | Greenberg | Finance | 12000.00 | 1
Susan | Mavris | Human Resources | 6500.00 | 1
Alexander | Hunold | IT | 9000.00 | 1
Michael | Hartstein | Marketing | 13000.00 | 1
Hermann | Baer | Public Relations | 10000.00 | 1
Den | Raphaely | Purchasing | 11000.00 | 1
John | Russell | Sales | 14000.00 | 1
Adam | Fripp | Shipping | 8200.00 | 1
Code language: SQL (Structured Query Language) (sql)
Summary #
- Use the SQL
DENSE_RANK()
function to rank rows in partitions without gaps in ranking values.
Databases #
- PostgreSQL DENSE_RANK function
- Oracle DENSE_RANK function
- SQL Server DENSE_RANK function
- MySQL DENSE_RANK function
- SQLite DENSE_RANK function