SQL SELECT DISTINCT
A plain SELECT returns one result row for every table row, so the same value often appears many times. SELECT DISTINCT removes the duplicates and returns each unique value, or each unique combination of values, only once.
- List the unique values of a column
- Get distinct combinations of several columns
- Count unique values with
COUNT(DISTINCT ...) - How
DISTINCThandlesNULL
Sample data
| emp_id | first_name | dept_id | job_title | city |
|---|---|---|---|---|
| 100 | Meera | NULL | CEO | Mumbai |
| 101 | Asha | 1 | Engineering Manager | Bengaluru |
| 102 | Rahul | 1 | Senior Developer | Bengaluru |
| 103 | Priya | 1 | QA Engineer | Pune |
| 104 | Karan | 1 | Developer | Bengaluru |
| 105 | Vikram | 2 | Sales Manager | Mumbai |
| 106 | Neha | 2 | Sales Executive | Mumbai |
| 107 | Arjun | 2 | Sales Executive | Kolkata |
| 108 | Kavya | 3 | Marketing Lead | Pune |
| 109 | Rohan | 3 | Content Writer | Pune |
| 110 | Sneha | 4 | HR Manager | Delhi |
| 111 | Amit | 1 | Intern | Bengaluru |
Duplicates without DISTINCT
Which cities do our employees work in?
SELECT cityFROM employeesORDER BY city;| city |
|---|
| Bengaluru |
| Bengaluru |
| Bengaluru |
| Bengaluru |
| Delhi |
| Kolkata |
| Mumbai |
| Mumbai |
| Mumbai |
| Pune |
| Pune |
| Pune |
The result has 12 rows because there are 12 employees: Bengaluru and Pune appear several times.
SELECT DISTINCT on one column
SELECT DISTINCT cityFROM employeesORDER BY city;| city |
|---|
| Bengaluru |
| Delhi |
| Kolkata |
| Mumbai |
| Pune |
FROM employeesreads all 12 rows.SELECT citykeeps only thecitycolumn.DISTINCTcompares the rows of the result and keeps one copy of each value: 12 rows shrink to 5 cities.ORDER BY citysorts them alphabetically.
DISTINCT on several columns
With more than one column, DISTINCT removes rows where all the listed columns are the same. It works on the combination, not on each column separately:
SELECT DISTINCT dept_id, cityFROM employeesORDER BY dept_id, city;| dept_id | city |
|---|---|
| NULL | Mumbai |
| 1 | Bengaluru |
| 1 | Pune |
| 2 | Kolkata |
| 2 | Mumbai |
| 3 | Pune |
| 4 | Delhi |
- MySQL builds
(dept_id, city)pairs for all 12 employees. - Pairs that occur more than once, such as
(1, Bengaluru)for four engineers, are kept once. - Department 1 still appears twice, because it has two different cities: Bengaluru and Pune.
- The CEO’s pair
(NULL, Mumbai)is a combination of its own.
DISTINCT and NULL
DISTINCT treats all NULLs as equal, so they collapse into one NULL row:
SELECT DISTINCT commissionFROM employeesORDER BY commission;| commission |
|---|
| NULL |
| 4500 |
| 6000 |
| 12000 |
- Nine employees have no commission (
NULL) and three sales staff have one. - The nine
NULLs become a singleNULLrow, and the three amounts are all different. - In ascending order MySQL puts
NULLfirst.
COUNT(DISTINCT column)
To count how many different values a column has, put DISTINCT inside COUNT:
SELECT COUNT(*) AS employees, COUNT(city) AS rows_with_city, COUNT(DISTINCT city) AS different_cities, COUNT(DISTINCT dept_id) AS departments_usedFROM employees;| employees | rows_with_city | different_cities | departments_used |
|---|---|---|---|
| 12 | 12 | 5 | 4 |
COUNT(*)counts every row: 12.COUNT(city)counts rows wherecityis not NULL: also 12.COUNT(DISTINCT city)counts unique cities: 5.COUNT(DISTINCT dept_id)ignores the CEO’s NULL and counts 4 departments.
Which customers have placed at least one order? DISTINCT turns “one row per order” into “one row per customer”:
SELECT DISTINCT customer_idFROM ordersORDER BY customer_id;| customer_id |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
DISTINCT vs GROUP BY
SELECT DISTINCT city FROM employees and SELECT city FROM employees GROUP BY city return the same rows. Use DISTINCT when you only want unique rows; use GROUP BY when you also want a count, sum or other aggregate per group:
SELECT city, COUNT(*) AS staffFROM employeesGROUP BY cityORDER BY staff DESC, city;| city | staff |
|---|---|
| Bengaluru | 4 |
| Mumbai | 3 |
| Pune | 3 |
| Delhi | 1 |
| Kolkata | 1 |
DISTINCT is not a fix for a wrong join. If a query returns unexpected duplicates, find out why (often a missing join condition) instead of hiding them with DISTINCT. Removing duplicates also costs time on large results.
Exercise: Unique job titles
List each distinct job_title in the employees table, sorted alphabetically.
| job_title |
|---|
| CEO |
| Content Writer |
| Developer |
| Engineering Manager |
| HR Manager |
| Intern |
| Marketing Lead |
| QA Engineer |
| Sales Executive |
| Sales Manager |
| Senior Developer |
Hint 1
Put DISTINCT straight after SELECT.
SELECT DISTINCT job_titleFROM employeesORDER BY job_title;| job_title |
|---|
| CEO |
| Content Writer |
| Developer |
| Engineering Manager |
| HR Manager |
| Intern |
| Marketing Lead |
| QA Engineer |
| Sales Executive |
| Sales Manager |
| Senior Developer |
Exercise: How many product categories?
Count how many different category values the products table has. Name the column categories.
| categories |
|---|
| 3 |
Hint 1
Use COUNT(DISTINCT category).
SELECT COUNT(DISTINCT category) AS categoriesFROM products;| categories |
|---|
| 3 |
Quick quiz
1. SELECT DISTINCT dept_id, city removes a row when…
DISTINCT applies to the whole combination of selected columns.
2. A column has the values 5, NULL, 5, NULL. What does SELECT DISTINCT return?
All NULLs count as one value for DISTINCT.
3. What does COUNT(DISTINCT city) count?
COUNT(DISTINCT x) counts unique non-NULL values.
SELECT DISTINCT FAQ
What does SELECT DISTINCT do in SQL?
It removes duplicate rows from the result, so each unique value or combination of values appears once.
Does DISTINCT apply to all columns?
Yes. DISTINCT always applies to the whole row of selected columns. There is no way to make it apply to only the first column; use GROUP BY or a window function for that.
Is DISTINCT faster than GROUP BY?
For simply removing duplicates, MySQL usually runs both the same way. Choose the one that states your intent: DISTINCT for unique rows, GROUP BY when you aggregate.
How do I count distinct values in SQL?
Use COUNT(DISTINCT column). It counts the different non-NULL values of the column.