SQL SELECT DISTINCT: Remove Duplicate Rows
SELECT DISTINCT returns each different row once. The 200 Playground orders were shipped to 20 cities, so SELECT DISTINCT shipping_city FROM orders gives 20 rows instead of 200. With several columns, it is the combination that has to be unique.
What Does DISTINCT Do?
Without DISTINCT, every row comes back, duplicates included. Compare the number of order rows with the number of different statuses:
SELECT COUNT(status) AS status_values,
COUNT(DISTINCT status) AS different_statuses
FROM orders;
▶ Run this query in the SQL Playground
| status_values | different_statuses |
|---|---|
| 200 | 6 |
DISTINCT lists those different values:
SELECT DISTINCT status
FROM orders
ORDER BY status;
▶ Run this query in the SQL Playground
| status |
|---|
| cancelled |
| delivered |
| pending |
| processing |
| refunded |
| shipped |
SELECT DISTINCT column_1, column_2, ...
FROM table
[WHERE ...]
[ORDER BY ...];
DISTINCT goes right after SELECT and applies to the whole row of selected columns. It is removed from the result after the rows are found; it does not change how they are read from the table.
DISTINCT With Multiple Columns
With more than one column, a row is a duplicate only if every selected column matches. Each department and city where employees work:
SELECT DISTINCT department, city
FROM employees
WHERE department = 'Engineering'
ORDER BY city;
▶ Run this query in the SQL Playground
| department | city |
|---|---|
| Engineering | Fort Worth |
| Engineering | Houston |
| Engineering | Jacksonville |
| Engineering | Philadelphia |
| Engineering | San Diego |
| Engineering | San Jose |
Engineering appears on several rows because it has employees in several cities. Each department and city pair appears once.
SELECT DISTINCT(department), city looks as if it applies to department only, but the brackets are just around a column; DISTINCT still applies to the pair. PostgreSQL has DISTINCT ON (column) for "one row per value of this column", which other databases do not support.Counting Unique Values
COUNT(DISTINCT column) counts different values instead of rows. How many customers have ordered, compared with how many orders there are:
SELECT COUNT(*) AS orders,
COUNT(DISTINCT user_id) AS customers_who_ordered,
COUNT(DISTINCT shipping_city) AS cities
FROM orders;
▶ Run this query in the SQL Playground
| orders | customers_who_ordered | cities |
|---|---|---|
| 200 | 114 | 20 |
It works per group too. Distinct customers per order status:
SELECT status,
COUNT(*) AS orders,
COUNT(DISTINCT user_id) AS customers
FROM orders
GROUP BY status
ORDER BY orders DESC;
▶ Run this query in the SQL Playground
| status | orders | customers |
|---|---|---|
| delivered | 82 | 65 |
| processing | 28 | 24 |
| cancelled | 27 | 25 |
| pending | 23 | 22 |
| shipped | 21 | 20 |
| refunded | 19 | 18 |
SQLite and SQL Server accept only one column inside COUNT(DISTINCT ...). To count distinct pairs, count the rows of a DISTINCT subquery: SELECT COUNT(*) FROM (SELECT DISTINCT department, city FROM employees). MySQL and PostgreSQL also accept COUNT(DISTINCT department, city) or a row value.
DISTINCT and NULL
For DISTINCT, all NULLs count as the same value, so NULL appears at most once in the result. COUNT(DISTINCT ...) leaves NULL out entirely:
SELECT COUNT(DISTINCT manager_id) AS distinct_managers,
(SELECT COUNT(*) FROM (SELECT DISTINCT manager_id FROM employees)) AS distinct_rows_including_null
FROM employees;
▶ Run this query in the SQL Playground
| distinct_managers | distinct_rows_including_null |
|---|---|
| 10 | 11 |
There are 10 different managers. SELECT DISTINCT returns one more row, the single NULL for employees who have no manager.
DISTINCT vs GROUP BY
For a plain list of unique values, these two queries return the same rows:
SELECT category
FROM products
GROUP BY category
ORDER BY category;
▶ Run this query in the SQL Playground
| category |
|---|
| Automotive |
| Books |
| Clothing |
| Electronics |
| Food & Beverage |
| Health & Beauty |
| Home & Garden |
| Office Supplies |
| Sports & Outdoors |
| Toys |
SELECT DISTINCT category
FROM products
ORDER BY category;
| DISTINCT | GROUP BY | |
|---|---|---|
| Purpose | Remove duplicate rows | Build groups to aggregate |
| Aggregates per value | No | Yes: COUNT, SUM, AVG ... per group |
| Filter on the groups | No | HAVING |
| Performance for a plain list | Usually identical | Usually identical |
Use DISTINCT when you only want the list; use GROUP BY as soon as you want a number per value.
DISTINCT With ORDER BY and LIMIT
DISTINCT is applied before ORDER BY and LIMIT, so LIMIT 5 gives five different values:
SELECT DISTINCT shipping_city
FROM orders
ORDER BY shipping_city
LIMIT 5;
▶ Run this query in the SQL Playground
| shipping_city |
|---|
| Austin |
| Charlotte |
| Chicago |
| Columbus |
| Dallas |
Most databases only let you ORDER BY columns that are in the SELECT DISTINCT list. Sorting by a column that is not selected would be ambiguous: which of the duplicate rows should decide the position?
Common DISTINCT Mistakes
Five errors and how to avoid them.
1. Expecting DISTINCT to apply to one column only
SELECT DISTINCT department, first_name
FROM employees;
SELECT DISTINCT department
FROM employees;
DISTINCT works on the whole selected row. Every extra column makes more rows distinct.
2. DISTINCT outside COUNT
SELECT DISTINCT COUNT(user_id)
FROM orders;
SELECT COUNT(DISTINCT user_id)
FROM orders;
Outside, DISTINCT de-duplicates the single result row; inside, it de-duplicates the values before counting.
3. Using DISTINCT to hide a join problem
SELECT DISTINCT u.id, u.first_name
FROM users u
JOIN orders o ON o.user_id = u.id;
SELECT u.id, u.first_name
FROM users u
WHERE EXISTS (SELECT 1 FROM orders o
WHERE o.user_id = u.id);
The join creates one row per order. If you only need users who ordered, EXISTS says so without producing duplicates to remove.
4. Writing UNIQUE instead of DISTINCT
SELECT UNIQUE category FROM products;
SELECT DISTINCT category FROM products;
UNIQUE only works in Oracle as a synonym. DISTINCT works everywhere.
5. DISTINCT on large results by habit
SELECT DISTINCT id, email
FROM users;
SELECT id, email
FROM users;
id is already unique, so DISTINCT only adds work. On large tables that work is noticeable.
Practice DISTINCT Queries
5 exercises on the real Playground tables.
Write each query yourself first. Every solution has been run against the Playground database.
-
1Easy List every department name once, in alphabetical order. Table:
employeesShow solution
SELECT DISTINCT department FROM employees ORDER BY department;▶ Run this query in the SQL Playground
DISTINCT removes the repeats; ORDER BY sorts them.
-
2Easy How many different countries do users come from? Table:
usersShow solution
SELECT COUNT(DISTINCT country) AS countries FROM users;▶ Run this query in the SQL Playground
COUNT(DISTINCT ...) counts each country once.
-
3Medium List each payment method together with each status it has had. Table:
paymentsShow solution
SELECT DISTINCT method, status FROM payments ORDER BY method, status;▶ Run this query in the SQL Playground
With two columns, each method and status pair appears once.
-
4Medium How many different products have been ordered, and in how many different orders? Table:
order_itemsShow solution
SELECT COUNT(DISTINCT product_id) AS products_ordered, COUNT(DISTINCT order_id) AS orders FROM order_items;▶ Run this query in the SQL Playground
Two COUNT(DISTINCT ...) in one query, each on its own column.
-
5Medium For each department, count the different cities its employees work in. Table:
employeesShow solution
SELECT department, COUNT(DISTINCT city) AS cities FROM employees GROUP BY department ORDER BY cities DESC, department;▶ Run this query in the SQL Playground
COUNT(DISTINCT city) runs once per department group.
📝 Quiz — DISTINCT
Test your understanding · 0/5 answered
What does SELECT DISTINCT do?
Duplicates of the whole selected row are removed.
Which query lists each department once?
DISTINCT goes right after SELECT. UNIQUE only works in Oracle.
What is treated as unique in SELECT DISTINCT department, city?
All selected columns together.
How do you find which payment methods are used in a large payments table?
GROUP BY method would also work if you selected method; the option shown only returns counts.
Which statement about DISTINCT is false?
DISTINCT works on the result rows, after they are found.
DISTINCT Interview Questions
Q1. What is the difference between DISTINCT and GROUP BY?
For a plain list they return the same rows and usually perform the same. GROUP BY is needed when you want aggregates per value or a HAVING filter.
Q2. How does DISTINCT treat NULL?
All NULLs count as one value, so NULL appears at most once. COUNT(DISTINCT col) ignores NULLs completely.
Q3. How do you count distinct combinations of two columns?
SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t) x works everywhere. MySQL also allows COUNT(DISTINCT a, b).
Q4. Why is SELECT DISTINCT after a JOIN often a warning sign?
It usually removes duplicates the join created. If the duplicates are not wanted, EXISTS or a corrected join condition is clearer and avoids producing them.
Q5. What is DISTINCT ON in PostgreSQL?
It keeps the first row for each value of the listed columns, using ORDER BY to decide which row is first. Other databases use ROW_NUMBER() for the same result.
Frequently Asked Questions
What does SELECT DISTINCT do in SQL?
SELECT DISTINCT removes duplicate rows from the result, so each different row appears once. SELECT DISTINCT status FROM orders returns the six statuses instead of 200 rows.
Can SELECT DISTINCT work with multiple columns?
Yes. DISTINCT applies to the combination of all selected columns: SELECT DISTINCT department, city returns each department and city pair once.
Is SELECT DISTINCT the same as GROUP BY?
For a plain list of unique values, they return the same rows. GROUP BY is the one to use when you also want a count, sum or average per value.
How does DISTINCT handle NULL values in SQL?
DISTINCT treats all NULLs as one value, so NULL appears at most once. COUNT(DISTINCT column) does not count NULL at all.
How do you count unique values in SQL?
Use COUNT(DISTINCT column). SELECT COUNT(DISTINCT user_id) FROM orders counts the different customers who placed orders: 114 in the Playground.
Can I use SELECT DISTINCT with ORDER BY?
Yes. DISTINCT is applied first and ORDER BY then sorts the unique rows. Most databases only allow ORDER BY on the columns in the SELECT DISTINCT list.
Where can I practise SELECT DISTINCT queries?
In the SQLabHub Playground: every query on this page has a "Run this query" link that opens it there against the same practice database.