When you query a table, the result set often contains repeated values. For example, if you list the countries of every customer, the same country name appears many times. The DISTINCT keyword tells the database to return only unique values, removing duplicates from the result.
In this tutorial you will learn what DISTINCT does, how to apply it to one or several columns, how it interacts with NULL, and when to prefer alternatives such as GROUP BY.
Prerequisites
To follow along you should be comfortable with:
- writing a basic
SELECTstatement; - filtering rows with
WHERE; - running SQL against a local database (PostgreSQL, MySQL, MariaDB, SQL Server, Oracle Database, or SQLite).
If you are new to SELECT, review a beginner SELECT tutorial first.
Sample Database
We will use a small online bookstore schema. Create the table and insert the sample data below.
CREATE TABLE books (
book_id INTEGER PRIMARY KEY,
title VARCHAR(200) NOT NULL,
author_name VARCHAR(100) NOT NULL,
genre VARCHAR(50),
language VARCHAR(30) NOT NULL,
published_year INTEGER
);
INSERT INTO books (book_id, title, author_name, genre, language, published_year) VALUES
(1, 'The Silent River', 'Anna Novak', 'Fiction', 'English', 2019),
(2, 'Cooking with Herbs', 'Marco Bianchi', 'Cooking', 'English', 2021),
(3, 'Distant Galaxies', 'Anna Novak', 'Science', 'English', 2022),
(4, 'La Cucina Italiana', 'Marco Bianchi', 'Cooking', 'Italian', 2020),
(5, 'Silent Mountains', 'Chen Wei', 'Fiction', 'English', 2019),
(6, 'Introduction to Botany', 'Priya Sharma', 'Science', 'English', 2018),
(7, 'Recipes from Home', 'Marco Bianchi', 'Cooking', 'Italian', 2023),
(8, 'Untitled Draft', 'Anna Novak', NULL, 'English', 2024),
(9, 'Notes on Rivers', 'Chen Wei', NULL, 'English', 2020);
Basic Syntax
Place DISTINCT immediately after SELECT:
SELECT DISTINCT column_name
FROM table_name;
DISTINCTapplies to the entire row produced by theSELECTlist, not to a single column in isolation.- When you list multiple columns, uniqueness is evaluated across the whole combination.
Practical Example
Suppose the marketing team wants a list of every genre carried by the bookstore, without duplicates.
SELECT DISTINCT genre
FROM books;
The database reads every row in books, extracts the genre value, and returns each unique value once.
Expected Result
| genre |
|---|
| Fiction |
| Cooking |
| Science |
| NULL |
Two rows contain NULL in genre, but DISTINCT collapses them into a single NULL in the output. DISTINCT treats NULL values as equal to each other for the purpose of removing duplicates, even though NULL = NULL is not true in general SQL comparisons.
Additional Examples
DISTINCT on Multiple Columns
Uniqueness is calculated across the combination of listed columns.
SELECT DISTINCT
author_name,
language
FROM books;
Expected result:
| author_name | language |
|---|---|
| Anna Novak | English |
| Marco Bianchi | English |
| Marco Bianchi | Italian |
| Chen Wei | English |
| Priya Sharma | English |
Marco Bianchi appears twice because he has books in two different languages. The pair (Marco Bianchi, English) is distinct from (Marco Bianchi, Italian).
Combining DISTINCT with WHERE
Filter rows first, then remove duplicates:
SELECT DISTINCT author_name
FROM books
WHERE genre = 'Cooking';
Expected result:
| author_name |
|---|
| Marco Bianchi |
Combining DISTINCT with ORDER BY
You can sort the unique values. Every column in ORDER BY must also appear in the SELECT list when using DISTINCT.
SELECT DISTINCT genre
FROM books
WHERE genre IS NOT NULL
ORDER BY genre ASC;
Counting Unique Values
To count how many unique values exist, wrap the column in COUNT(DISTINCT ...):
SELECT COUNT(DISTINCT author_name) AS unique_authors
FROM books;
Expected result:
| unique_authors |
|---|
| 4 |
Note that COUNT(DISTINCT column_name) ignores NULL values, which is different from how DISTINCT behaves in a SELECT list.
DISTINCT vs. GROUP BY
The following two queries produce the same set of unique genres:
SELECT DISTINCT genre
FROM books;
SELECT genre
FROM books
GROUP BY genre;
Prefer DISTINCT when you only need unique values. Prefer GROUP BY when you also need aggregate values per group, such as counts or sums:
SELECT
genre,
COUNT(*) AS book_count
FROM books
GROUP BY genre;
Common Mistakes
Applying DISTINCT to One Column Expecting per-Column Uniqueness
Incorrect assumption:
SELECT DISTINCT author_name, title
FROM books;
Readers sometimes expect this to return one row per unique author_name. It does not. DISTINCT considers the entire selected row, and every title is unique, so no rows are collapsed.
If you want one author per row, select only author_name:
SELECT DISTINCT author_name
FROM books;
Using DISTINCT to Hide a Faulty JOIN
Adding DISTINCT to remove duplicate rows caused by an incorrect join often masks a real problem. Instead, review the join condition, the relationships between tables, and whether a one-to-many relationship is producing the extra rows.
Assuming DISTINCT Sorts the Result
DISTINCT does not guarantee any specific ordering. If the order matters, add an explicit ORDER BY clause.
Database Compatibility
SELECT DISTINCT is part of standard SQL and works in:
- PostgreSQL;
- MySQL;
- MariaDB;
- SQL Server;
- Oracle Database;
- SQLite.
PostgreSQL additionally supports a non-standard extension, DISTINCT ON, which keeps the first row per group according to ORDER BY:
SELECT DISTINCT ON (author_name)
author_name,
title,
published_year
FROM books
ORDER BY author_name, published_year DESC;
This returns the most recently published book per author. DISTINCT ON is not portable, so avoid it in code that must run on other databases.
Best Practices
- List only the columns you need.
DISTINCTon many columns is expensive because the database must compare every column value. - Filter first with
WHERE. Reducing the row set before applyingDISTINCTlowers the work required. - Prefer
GROUP BYwhen you need aggregates. Do not combineDISTINCTwithGROUP BYunless you have a specific reason. - Add
ORDER BYwhen order matters.DISTINCTdoes not sort. - Measure performance on large tables.
DISTINCTmay require sorting or hashing the entire result. Inspect the execution plan withEXPLAINto understand the cost. The exact syntax and output ofEXPLAINvary between database systems. - Handle
NULLdeliberately. Remember thatDISTINCTtreats allNULLvalues as one group, whileCOUNT(DISTINCT column_name)ignores them entirely.
Conclusion
You learned how to use the SQL DISTINCT keyword to remove duplicate rows from a result set, how it applies to one or more columns, how it interacts with NULL, and how it compares to GROUP BY. Use DISTINCT when you need a clean list of unique values, and switch to GROUP BY when you also need aggregate information per group.
