SELECT DISTINCT

SELECT DISTINCT explained with practical SQL patterns, edge cases, and production-ready guidance.

5 min read · Last updated: March 2026 · Back to overview

Quick Answer

SELECT DISTINCT removes duplicate rows from a query result set, keeping one row per unique value or combination of values in the specified columns. PostgreSQL treats NULL as equal for the purposes of deduplication — multiple NULLs collapse to one.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

Introduction to PostgreSQL SELECT DISTINCT

By default, a SELECT statement can return multiple rows with identical values. SELECT DISTINCT eliminates those duplicates, retaining only one row for each unique value (or combination of values) in the specified columns.

The basic syntax for a single column:

SELECT DISTINCT column1
FROM table_name;

For multiple columns, DISTINCT evaluates uniqueness based on the combination of all listed columns:

SELECT DISTINCT column1, column2
FROM table_name;

To find distinct rows across all columns, use SELECT DISTINCT *:

SELECT DISTINCT *
FROM table_name;

SELECT DISTINCT examples

Consider a colors table with bcolor and fcolor columns containing these rows:

id | bcolor | fcolor
----+--------+--------
 1 | red    | red
 2 | red    | red
 3 | red    | null
 4 | null   | red
 5 | null   | null
 6 | green  | green
 7 | blue   | blue
 8 | blue   | blue

Distinct values on one column:

SELECT DISTINCT bcolor
FROM colors
ORDER BY bcolor;

Result:

bcolor
--------
blue
green
red
null
(4 rows)

The three red rows collapse to one, the two blue rows collapse to one, and both NULLs collapse to one NULL.

Distinct on multiple columns:

SELECT DISTINCT bcolor, fcolor
FROM colors
ORDER BY bcolor, fcolor;

Result:

bcolor | fcolor
--------+--------
blue   | blue
green  | green
red    | red
red    | null
null   | red
null   | null
(6 rows)

Here, (red, red) appears twice in the original table but is collapsed to one row. (red, null) only appears once, so it is kept as-is.

Practical use: auditing unique values

A common real-world use of SELECT DISTINCT is discovering what distinct values exist in a column before writing filter logic. For example, finding all distinct rental rates in a film catalog:

SELECT DISTINCT rental_rate
FROM film
ORDER BY rental_rate;

Result:

rental_rate
-------------
       0.99
       2.99
       4.99
(3 rows)

This confirms there are exactly three rental rate tiers, which you can then use in an IN clause or application logic.

How SELECT DISTINCT handles NULL

PostgreSQL treats NULL as a duplicate of another NULL for the purpose of DISTINCT. So if a column contains five NULL values, SELECT DISTINCT returns only one NULL. This is different from how = comparison works (where NULL = NULL is never TRUE).

SELECT DISTINCT vs. GROUP BY

  • SELECT DISTINCT col and SELECT col FROM t GROUP BY col produce the same unique-value result, but GROUP BY lets you add aggregate functions like COUNT(*).
  • For simply listing unique values without aggregation, SELECT DISTINCT is more concise and often clearer in intent.
  • Performance is typically similar; for very large tables, check EXPLAIN ANALYZE to see whether a HashAggregate or Sort-based dedup is used.

Reference: PostgreSQL documentation — SELECT DISTINCT.

Continue in Querying Data: DISTINCT ON.

Related in this section: PostgreSQL SELECT · Column Aliases · ORDER BY

Frequently Asked Questions

What is the difference between SELECT DISTINCT and SELECT DISTINCT ON in PostgreSQL?

SELECT DISTINCT removes rows that are completely identical across all listed columns. SELECT DISTINCT ON (column) keeps the first row per unique value of the specified column, allowing other columns in the row to vary — it requires an ORDER BY clause to determine which "first" row is kept. DISTINCT ON is a PostgreSQL-specific extension not available in standard SQL.

Does SELECT DISTINCT work on multiple columns?

Yes. SELECT DISTINCT col1, col2 evaluates uniqueness based on the combination of values in both columns. A row is only removed if another row has the same values in all listed columns simultaneously.

How does SELECT DISTINCT handle NULL values?

PostgreSQL treats NULLs as equal for DISTINCT purposes. Multiple rows where the column is NULL will be collapsed into a single NULL row in the result. This differs from equality comparisons where NULL = NULL evaluates to NULL (unknown), not TRUE.

Is SELECT DISTINCT the same as GROUP BY?

They produce the same unique-value output for simple cases: SELECT DISTINCT col and SELECT col FROM t GROUP BY col return identical results. The difference is that GROUP BY supports aggregate functions like COUNT(*) or SUM() alongside the grouped column, while SELECT DISTINCT does not.

Can SELECT DISTINCT slow down my query?

Yes. DISTINCT forces PostgreSQL to deduplicate the result, which typically involves sorting or hashing all rows. On large tables this can be expensive. If you only need unique values from an indexed column, PostgreSQL may use an Index Scan with fast skip logic — check EXPLAIN output. Consider whether GROUP BY or a subquery with EXISTS might serve your use case more efficiently.