Using ROW_NUMBER, RANK, and DENSE_RANK in PostgreSQL
📖 Scenario: You work for a company that wants to analyze sales data to see how salespeople rank based on their monthly sales.The company wants to assign ranks to salespeople to identify top performers, handle ties properly, and also assign unique row numbers for each salesperson.
🎯 Goal: Build a PostgreSQL query that uses ROW_NUMBER(), RANK(), and DENSE_RANK() window functions to rank salespeople by their sales amount in descending order.
📋 What You'll Learn
Create a table called sales with columns salesperson (text) and sales_amount (integer).
Insert the exact sales data provided into the sales table.
Write a query that selects all columns and adds three new columns: row_num using ROW_NUMBER(), rank_num using RANK(), and dense_rank_num using DENSE_RANK(), all ordered by sales_amount descending.
Ensure the query orders the final output by sales_amount descending.
💡 Why This Matters
🌍 Real World
Ranking salespeople or items by performance is common in business reports and dashboards to identify top performers and handle ties correctly.
💼 Career
Understanding and using window functions like ROW_NUMBER, RANK, and DENSE_RANK is essential for data analysts and database developers to create advanced queries for reporting and analytics.
Progress0 / 4 steps
1
Create the sales table and insert data
Create a table called sales with columns salesperson (text) and sales_amount (integer). Then insert these exact rows: ('Alice', 500), ('Bob', 700), ('Charlie', 700), ('Diana', 400), ('Evan', 500).
PostgreSQL
Hint
Use CREATE TABLE to define the table and INSERT INTO with multiple rows to add the data.
2
Set up the base SELECT query
Write a SELECT query that selects all columns from the sales table. This will be the base for adding ranking functions.
PostgreSQL
Hint
Use a simple SELECT statement to get started.
3
Add ROW_NUMBER(), RANK(), and DENSE_RANK() columns
Modify the SELECT query to add three new columns: row_num using ROW_NUMBER() OVER (ORDER BY sales_amount DESC), rank_num using RANK() OVER (ORDER BY sales_amount DESC), and dense_rank_num using DENSE_RANK() OVER (ORDER BY sales_amount DESC).
PostgreSQL
Hint
Use window functions with OVER (ORDER BY sales_amount DESC) to assign ranks.
4
Order the final output by sales_amount descending
Add an ORDER BY sales_amount DESC clause at the end of the SELECT query to sort the results by sales amount from highest to lowest.
PostgreSQL
Hint
Use ORDER BY sales_amount DESC to sort the final results.
Practice
(1/5)
1. What does the ROW_NUMBER() function do in PostgreSQL?
easy
A. Counts the total number of rows in the table.
B. Assigns the same rank to rows with identical values, skipping ranks after ties.
C. Assigns ranks to rows without skipping numbers after ties.
D. Assigns a unique sequential number to each row in the result set.
Solution
Step 1: Understand ROW_NUMBER() purpose
ROW_NUMBER() gives each row a unique sequential number, starting at 1.
Step 2: Compare with RANK() and DENSE_RANK()
Unlike RANK() or DENSE_RANK(), ROW_NUMBER() never assigns the same number to multiple rows.
Final Answer:
Assigns a unique sequential number to each row in the result set. -> Option D
Quick Check:
ROW_NUMBER() = unique row numbers [OK]
Hint: ROW_NUMBER always gives unique numbers, no ties allowed [OK]
Common Mistakes:
Confusing ROW_NUMBER with RANK or DENSE_RANK
Thinking ROW_NUMBER skips numbers after ties
Assuming ROW_NUMBER counts total rows
2. Which of the following is the correct syntax to assign a rank using RANK() over a column named score ordered descending?
easy
A. SELECT RANK(score) OVER (ORDER BY DESC) FROM table_name;
B. SELECT RANK() ORDER BY score DESC FROM table_name;
C. SELECT RANK() OVER (ORDER BY score DESC) FROM table_name;
D. SELECT RANK() OVER (PARTITION BY score DESC) FROM table_name;
Solution
Step 1: Recall correct RANK() syntax
RANK() is used with OVER() clause specifying ORDER BY column and direction.
Step 2: Check each option
SELECT RANK() OVER (ORDER BY score DESC) FROM table_name; correctly uses RANK() OVER (ORDER BY score DESC). Others misuse syntax or clauses.
Final Answer:
SELECT RANK() OVER (ORDER BY score DESC) FROM table_name; -> Option C
Quick Check:
RANK() OVER (ORDER BY column DESC) syntax [OK]
Hint: RANK() needs OVER with ORDER BY column [OK]
Common Mistakes:
Putting column inside RANK() function
Using PARTITION BY incorrectly
Omitting OVER() clause
3. Given the table players with columns name and score, what will be the output of this query?
SELECT name, score, RANK() OVER (ORDER BY score DESC) AS rank FROM players;
Data: name | score
-----|------
Alice | 100
Bob | 90
Carol | 90
Dave | 80
Hint: RANK() skips numbers after ties, DENSE_RANK() does not [OK]
Common Mistakes:
Assuming ranks after ties are consecutive
Confusing RANK() with DENSE_RANK()
Misordering rows by score
4. Identify the error in this query:
SELECT name, DENSE_RANK(score) OVER (ORDER BY score DESC) FROM players;
medium
A. DENSE_RANK() should not have a column inside the parentheses.
B. DENSE_RANK() cannot be used without PARTITION BY clause.
C. ORDER BY clause is missing in the OVER() clause.
D. The query is correct and will run without errors.
Solution
Step 1: Check DENSE_RANK() syntax
DENSE_RANK() does not take any arguments inside parentheses; it is called as DENSE_RANK() OVER (...).
Step 2: Identify the error in the query
The query incorrectly uses DENSE_RANK(score), which causes a syntax error.
Final Answer:
DENSE_RANK() should not have a column inside the parentheses. -> Option A
Quick Check:
DENSE_RANK() has empty parentheses [OK]
Hint: Window functions have empty parentheses, column goes in ORDER BY [OK]
Common Mistakes:
Putting column inside DENSE_RANK()
Thinking PARTITION BY is mandatory
Omitting OVER() clause
5. You want to assign ranks to employees based on their sales, but you want no gaps in ranking numbers even if some employees have the same sales. Which function should you use and why?
Options: A) ROW_NUMBER() because it gives unique numbers. B) RANK() because it skips ranks after ties. C) DENSE_RANK() because it assigns ranks without gaps after ties. D) COUNT() because it counts rows.
hard
A. DENSE_RANK() because it assigns ranks without gaps after ties.
B. RANK() because it skips ranks after ties.
C. ROW_NUMBER() because it gives unique numbers.
D. COUNT() because it counts rows.
Solution
Step 1: Understand ranking requirements
The requirement is to assign ranks with no gaps even if employees tie in sales.
Step 2: Match functions to behavior
ROW_NUMBER() gives unique numbers, ignoring ties. RANK() skips ranks after ties causing gaps. DENSE_RANK() assigns ranks without gaps after ties.
Step 3: Choose correct function
DENSE_RANK() fits the requirement perfectly.
Final Answer:
DENSE_RANK() because it assigns ranks without gaps after ties. -> Option A
Quick Check:
DENSE_RANK() = no gaps in ranks [OK]
Hint: Use DENSE_RANK() to avoid gaps in ranking numbers [OK]
Common Mistakes:
Choosing RANK() and expecting no gaps
Using ROW_NUMBER() which ignores ties
Confusing COUNT() with ranking functions
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.