Using DISTINCT for Clean Data: A PostgreSQL Beginner's Guide
Learn how to use DISTINCT and DISTINCT ON in PostgreSQL to filter unique rows from your result sets and keep your data clean and accurate.

Previously in this course, we explored grouping data with GROUP BY to perform analytical calculations. While GROUP BY is perfect for aggregating metrics, sometimes you simply need to see a unique list of values or identify distinct categories without performing math. That is where the DISTINCT clause comes in.
When working with real-world data, you often end up with result sets containing redundant information. DISTINCT allows you to cut through the noise and return only unique rows.
Eliminating Duplicates with DISTINCT
The DISTINCT keyword is a modifier you place immediately after SELECT. It tells PostgreSQL to look at the combination of all columns in your query and return only unique rows.
If you have a table of orders and you want to know which unique customer_ids have placed an order, a standard SELECT might return hundreds of rows with repeating IDs. Using DISTINCT collapses those into a single list.
Worked Example: Extracting Unique Categories
Imagine our store database has a products table, but we’ve accidentally populated it with multiple entries per category. To retrieve a clean list of all available categories, we use:
SQLSELECT DISTINCT category FROM products;
If you select multiple columns, DISTINCT treats the entire row as a unique set. For example, SELECT DISTINCT category, supplier_id FROM products will return only rows where the combination of both columns is unique.
Advanced Filtering with DISTINCT ON

Standard DISTINCT is powerful, but sometimes it is too blunt. You might want to get one representative row per category—perhaps the most recently added product for each type.
For this, PostgreSQL provides a vendor-specific extension: DISTINCT ON.
Worked Example: Finding the Newest Product per Category
Suppose you want to see the latest product added to each category. Using DISTINCT ON (category) forces PostgreSQL to keep only the first row it encounters for each unique value in that column.
Crucially, you must include an ORDER BY clause to determine which row is "first."
SQLSELECT DISTINCT ON (category) product_name, category, created_at FROM products ORDER BY category, created_at DESC;
In this query:
DISTINCT ON (category)tells PostgreSQL to keep one row per unique category.ORDER BY category, created_at DESCensures that for every category, the row with the most recentcreated_attimestamp appears first, so it is the one kept.
Hands-on Exercise
Using our store's orders table:
- Write a query to find all unique
statusvalues (e.g., 'pending', 'shipped', 'cancelled'). - Write a query using
DISTINCT ONto find the most recent order date for each uniquecustomer_id.
Hint: Ensure you sort by the date in descending order to get the most recent record.
Common Pitfalls
- Forgetting ORDER BY with DISTINCT ON: If you use
DISTINCT ONwithout a correspondingORDER BYclause that starts with the same column, PostgreSQL cannot guarantee which row you will get. It will be effectively random. - Performance Impact:
DISTINCTrequires PostgreSQL to sort or hash the entire result set to identify duplicates. On tables with millions of rows, this can be slow. If you find your queries lagging, consider analyzing query plans to see if an index can speed up the operation. - Confusing it with GROUP BY: Use
DISTINCTwhen you want a unique list of items. UseGROUP BYwhen you need to perform calculations (likeSUMorCOUNT) on those items.
FAQ
Q: Can I use DISTINCT on only one column if I select multiple columns?
A: No. DISTINCT applies to the entire row combination. If you need a unique list of one column while keeping others, use DISTINCT ON.
Q: Is DISTINCT case-sensitive? A: Yes. 'Electronics' and 'electronics' are treated as two unique values.
Q: Does DISTINCT remove duplicates from the source table? A: Never. It only filters the result set returned to your client. Your stored data remains exactly as it was.
Recap
We have learned how to use DISTINCT to filter out redundant information and DISTINCT ON to retrieve specific, non-duplicate records based on your custom sorting criteria. These tools are essential for data cleanup and generating clean, readable reports from your store database.
Up next: We will dive into Common Table Expressions (CTEs) to break down complex, multi-step queries into readable, reusable segments.
Work with me

React & Next.js Dashboard / Admin UI Development
A clean, data-rich dashboard UI in React or Next.js — charts, tables, and real-time data that your users will actually enjoy using.

WordPress Speed Optimization, Malware & Bug Fixes
Slow, hacked, or broken WordPress site? I clean it up, speed it up, and lock it down — fast, by a 12-year WordPress veteran.


