SQL INTERSECT and EXCEPT
UNION combines two results. Its siblings compare them: INTERSECT returns the rows that appear in both results, and EXCEPT returns rows in the first result that are not in the second. MySQL added both in version 8.0.31, so MySQL 8.4 supports them; older versions need a join or EXISTS.
- Find common rows with
INTERSECT - Find missing rows with
EXCEPT - Understand the duplicate rules
- Rewrite them with
EXISTSfor older databases
The two lists
Cities of employees and of customers:
| emp_id | first_name | city |
|---|---|---|
| 100 | Meera | Mumbai |
| 101 | Asha | Bengaluru |
| 102 | Rahul | Bengaluru |
| 103 | Priya | Pune |
| 104 | Karan | Bengaluru |
| 105 | Vikram | Mumbai |
| 106 | Neha | Mumbai |
| 107 | Arjun | Kolkata |
| 108 | Kavya | Pune |
| 109 | Rohan | Pune |
| 110 | Sneha | Delhi |
| 111 | Amit | Bengaluru |
| customer_id | customer_name | city |
|---|---|---|
| 1 | Ananya Sharma | Mumbai |
| 2 | Rohit Kumar | Delhi |
| 3 | Fatima Khan | Hyderabad |
| 4 | David Fernandes | Goa |
| 5 | Ishita Bose | Kolkata |
| 6 | Manoj Pillai | Chennai |
| 7 | Sara Thomas | Bengaluru |
INTERSECT: rows in both
Cities where we have both an employee and a customer:
SELECT city FROM employeesINTERSECTSELECT city FROM customersORDER BY city;| city |
|---|
| Bengaluru |
| Delhi |
| Kolkata |
| Mumbai |
- The first query lists employee cities; the second, customer cities.
INTERSECTkeeps the cities that appear in both lists.- Like
UNION, it removes duplicates: Bengaluru, Delhi, Kolkata and Mumbai.
EXCEPT: rows in the first only
Cities with employees but no customers:
SELECT city FROM employeesEXCEPTSELECT city FROM customersORDER BY city;| city |
|---|
| Pune |
The order matters. Cities with customers but no employees:
SELECT city FROM customersEXCEPTSELECT city FROM employeesORDER BY city;| city |
|---|
| Chennai |
| Goa |
| Hyderabad |
A EXCEPT Bkeeps the rows of A that do not appear in B.- Swapping the queries asks the opposite question: Chennai, Goa and Hyderabad have customers but no staff.
Practical example: products never ordered
SELECT product_id FROM productsEXCEPTSELECT product_id FROM order_items;| product_id |
|---|
| 9 |
Several columns
The comparison uses the whole row, so all selected columns must match. Customer ids that ordered in both January and April 2025:
SELECT customer_id FROM orders WHERE order_date BETWEEN '2025-01-01' AND '2025-01-31'INTERSECTSELECT customer_id FROM orders WHERE order_date BETWEEN '2025-04-01' AND '2025-04-30';| customer_id |
|---|
| 1 |
| 2 |
Alternatives with EXISTS
On MySQL before 8.0.31 (and many interview answers), write INTERSECT with EXISTS and EXCEPT with NOT EXISTS:
SELECT DISTINCT e.cityFROM employees eWHERE NOT EXISTS (SELECT 1 FROM customers c WHERE c.city = e.city)ORDER BY e.city;| city |
|---|
| Pune |
- For each employee city, the subquery checks whether any customer has the same city.
NOT EXISTSkeeps the cities with no such customer: the same answer asEXCEPT.DISTINCTremoves repeats, whichEXCEPTdoes automatically. See EXISTS.
INTERSECT ALL and EXCEPT ALL keep duplicates (MySQL supports them too). Also note that, unlike = in WHERE, these operators treat two NULLs as equal.
Quick quiz
1. Which operator returns rows found in both queries?
INTERSECT keeps the common rows.
2. Is A EXCEPT B the same as B EXCEPT A?
EXCEPT removes the second result from the first.
3. From which MySQL version are INTERSECT and EXCEPT supported?
They were added in 8.0.31, so MySQL 8.4 has them.
INTERSECT and EXCEPT FAQ
Does MySQL support INTERSECT?
Yes, since MySQL 8.0.31. In older versions use an inner join or WHERE EXISTS.
What is the difference between EXCEPT and MINUS?
They do the same thing. Oracle calls it MINUS; standard SQL, PostgreSQL, SQL Server and MySQL use EXCEPT.
What is the difference between INTERSECT and INNER JOIN?
INTERSECT compares whole result rows and removes duplicates. An inner join combines columns of two tables on a condition and can multiply rows.