PostgreSQLDISTINCT & DISTINCT ON

DISTINCT & DISTINCT ON

DISTINCT removes duplicate rows from a result set. It is standard SQL and works exactly the way you would expect once you have seen it. PostgreSQL also offers a genuinely useful extension, DISTINCT ON, that has no direct equivalent in the SQL standard.
SELECT DISTINCT

Every distinct city customers live in

SQL
SELECT DISTINCT city
FROM customers
ORDER BY city;
DISTINCT considers the entire row (every selected column) when deciding what counts as a duplicate. Selecting more columns means fewer rows collapse together.

Distinct combinations of city and country

SQL
SELECT DISTINCT city, country
FROM customers
ORDER BY country, city;
COUNT(DISTINCT column)
Combine DISTINCT with an aggregate to count how many unique values appear, rather than how many rows match.

How many distinct customers have placed an order?

SQL
SELECT COUNT(DISTINCT customer_id) AS customers_with_orders
FROM orders;
DISTINCT ON: one row per group, PostgreSQL-style
DISTINCT ON (columns) keeps only the first row for each distinct value of the given columns, based on whatever ORDER BY you provide. This makes “give me one representative row per group” queries trivial to write.

The most recent order for each customer

SQL
SELECT DISTINCT ON (customer_id)
       customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;
Reading this: PostgreSQL groups the rows conceptually by customer_id, sorts each group by order_date DESC, and keeps only the first row of each group — that is, the most recent order per customer, all in a single pass with no subquery or window function required.
ORDER BY must start with the DISTINCT ON columns
The ORDER BY clause has to begin with the same column(s) named in DISTINCT ON, in the same order, before any tie-breaking columns. PostgreSQL uses that leading part of ORDER BY to know how rows are grouped; it uses the rest to decide which row within each group “wins.” Omitting this or getting the order wrong produces confusing, effectively arbitrary results.
Why PostgreSQL developers love DISTINCT ON
Getting “the latest row per group” in standard SQL usually requires a window function (ROW_NUMBER() OVER (...) wrapped in a subquery) or a correlated subquery joined back to the original table. DISTINCT ON expresses the exact same intent in one flat, readable query — it is one of the most-loved PostgreSQL-only conveniences.
  • DISTINCT compares whole rows across every selected column

  • COUNT(DISTINCT col) counts unique values rather than rows

  • DISTINCT ON (col) keeps the first row per value of col, according to ORDER BY

  • DISTINCT ON is PostgreSQL-specific — not portable to other databases