DISTINCT ON for unique per group in PostgreSQL - Time & Space Complexity
We want to understand how the time needed to run a query using DISTINCT ON changes as the data grows.
Specifically, how does finding one unique row per group scale with more rows?
Analyze the time complexity of the following code snippet.
SELECT DISTINCT ON (category) category, item, price
FROM products
ORDER BY category, price DESC;
This query selects the most expensive item for each category from the products table.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Scanning all rows in the products table to group by category.
- How many times: Once over all rows, then sorting them by category and price.
As the number of rows grows, the query must look at more data and sort more rows.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 rows scanned and sorted |
| 100 | About 100 rows scanned and sorted |
| 1000 | About 1000 rows scanned and sorted |
Pattern observation: The work grows roughly in proportion to the number of rows because sorting and scanning take more time as data grows.
Time Complexity: O(n log n)
This means the time grows a bit faster than the number of rows because sorting takes extra steps as data grows.
[X] Wrong: "DISTINCT ON just picks one row per group instantly, so it runs in constant time regardless of data size."
[OK] Correct: The database must first scan and sort the data to find the unique rows per group, so the time depends on how many rows there are.
Understanding how DISTINCT ON works helps you explain how databases handle grouping and sorting efficiently, a useful skill for real-world data tasks.
What if we added an index on the category and price columns? How would the time complexity change?
Practice
DISTINCT ON clause do in PostgreSQL?Solution
Step 1: Understand DISTINCT ON purpose
DISTINCT ONreturns only one row per group defined by the columns inside the parentheses.Step 2: Role of ORDER BY with DISTINCT ON
The row returned per group is the first row according to theORDER BYclause.Final Answer:
It returns one unique row per specified group based on the first row in ORDER BY. -> Option AQuick Check:
DISTINCT ON = unique per group [OK]
- Thinking DISTINCT ON removes all duplicates globally
- Ignoring ORDER BY affects which row is chosen
- Confusing DISTINCT ON with GROUP BY
DISTINCT ON?Solution
Step 1: Check DISTINCT ON syntax
The correct syntax requires parentheses around the column(s) for DISTINCT ON, likeDISTINCT ON (customer_id).Step 2: Verify ORDER BY matches DISTINCT ON
ORDER BY must start with the same columns as DISTINCT ON, herecustomer_id, then order byorder_date DESCto get latest order.Final Answer:
SELECT DISTINCT ON (customer_id) * FROM orders ORDER BY customer_id, order_date DESC; -> Option CQuick Check:
Correct syntax = SELECT DISTINCT ON (customer_id) * FROM orders ORDER BY customer_id, order_date DESC; [OK]
- Omitting parentheses around DISTINCT ON columns
- ORDER BY columns not starting with DISTINCT ON columns
- Using wrong columns in DISTINCT ON
sales with columns region, sale_date, and amount, what will this query return?SELECT DISTINCT ON (region) region, sale_date, amount FROM sales ORDER BY region, sale_date DESC;
Solution
Step 1: Analyze DISTINCT ON and ORDER BY
DISTINCT ON (region) picks one row per region. ORDER BY region, sale_date DESC orders rows by region and then newest sale_date first.Step 2: Determine which row is chosen per group
The first row per region after ordering is the one with the latest sale_date, so that row is returned.Final Answer:
One row per region with the latest sale_date. -> Option AQuick Check:
Latest per group = One row per region with the latest sale_date. [OK]
- Assuming earliest date instead of latest
- Thinking all rows are returned
- Believing syntax error due to ORDER BY
SELECT DISTINCT ON (user_id) user_id, login_time FROM logins ORDER BY login_time ASC;
Solution
Step 1: Check DISTINCT ON and ORDER BY columns
DISTINCT ON (user_id) requires ORDER BY to start withuser_idas the first column.Step 2: Identify mismatch in ORDER BY
ORDER BY only haslogin_time ASC, missinguser_idfirst, causing error.Final Answer:
DISTINCT ON columns must match the first columns in ORDER BY. -> Option DQuick Check:
ORDER BY start matches DISTINCT ON [OK]
- Ignoring ORDER BY column order
- Adding unnecessary GROUP BY
- Thinking ASC/DESC causes error
messages with columns chat_id, message_id, and sent_at. You want to get the most recent message per chat. Which query correctly achieves this?Solution
Step 1: Understand requirement for most recent message per chat
We want one row perchat_idwith the latestsent_at.Step 2: Check each option
SELECT DISTINCT ON (chat_id) chat_id, message_id, sent_at FROM messages ORDER BY chat_id, sent_at DESC; uses DISTINCT ON (chat_id) with ORDER BY chat_id, sent_at DESC, which returns the latest message per chat. SELECT DISTINCT ON (message_id) chat_id, message_id, sent_at FROM messages ORDER BY sent_at DESC; uses DISTINCT ON (message_id), which is unique per message, not per chat. SELECT chat_id, MAX(sent_at) FROM messages GROUP BY chat_id; returns only chat_id and max sent_at, missing message_id. SELECT chat_id, message_id, sent_at FROM messages WHERE sent_at = MAX(sent_at) GROUP BY chat_id; has invalid syntax mixing WHERE and GROUP BY incorrectly.Final Answer:
SELECT DISTINCT ON (chat_id) chat_id, message_id, sent_at FROM messages ORDER BY chat_id, sent_at DESC; -> Option BQuick Check:
Latest per group with DISTINCT ON = SELECT DISTINCT ON (chat_id) chat_id, message_id, sent_at FROM messages ORDER BY chat_id, sent_at DESC; [OK]
- Using DISTINCT ON on wrong column
- Trying GROUP BY without selecting all columns
- Incorrect WHERE with aggregate functions
Ready to prove it?
Pass the test and this pattern moves unknown
