INTERSECT, EXCEPT and Column Compatibility
The two set operations MySQL waited longest to add: rows in both sets, and rows in one set but not the other - plus how to emulate them where they are missing.
- SQL Basics
- DDL
- DML
- SELECT
- WHERE
- Functions
- NULL and Logic
- Aggregate Functions
- GROUP BY
- JOIN
- Subqueries
- Set Operations
- CTEs
- Constraints
- Keys
- Relationships
- Database Design
- Normalisation
- Views
- Window Functions
- Advanced SQL
- Procedures and Functions
- Triggers
- Temporary Tables
- Transactions
- Isolation and Locking
- Indexes
- Query Performance
- SQL Security
- SQL Dialects
- Practical SQL
Concept
INTERSECT returns rows present in both result sets. EXCEPT (spelled MINUS in Oracle) returns rows present in the first and absent from the second. Both remove duplicates by default.
| Operation | MySQL | MariaDB | PostgreSQL | SQL Server | Oracle | SQLite |
|---|---|---|---|---|---|---|
UNION | Yes | Yes | Yes | Yes | Yes | Yes |
INTERSECT | 8.0.31+ | 10.3+ | Yes | Yes | Yes | Yes |
EXCEPT | 8.0.31+ | 10.3+ | Yes | Yes | As MINUS | Yes |
Syntax
SELECT col FROM table_a
INTERSECT
SELECT col FROM table_b;
SELECT col FROM table_a
EXCEPT
SELECT col FROM table_b;Example
-- Cities that host both a department and a customer
SELECT location FROM departments WHERE location IS NOT NULL
INTERSECT
SELECT city FROM customers;
-- Cities with a department but no customer
SELECT location FROM departments WHERE location IS NOT NULL
EXCEPT
SELECT city FROM customers;Explanation
EXCEPT is directional: swapping the two queries answers the opposite question. INTERSECT is not - the order of the operands makes no difference to the result.
Both are set operations, so they de duplicate. If a city appears in departments three times, INTERSECT returns it once. INTERSECT ALL and EXCEPT ALL preserve multiplicity and exist in PostgreSQL and a few others, but they are rarely needed.
Emulating them where they are missing
-- INTERSECT, emulated with an inner join on distinct values
SELECT DISTINCT d.location
FROM departments d
JOIN customers c ON c.city = d.location;
-- INTERSECT, emulated with IN
SELECT DISTINCT location FROM departments
WHERE location IN (SELECT city FROM customers);
-- EXCEPT, emulated with NOT EXISTS (NULL safe)
SELECT DISTINCT d.location
FROM departments d
WHERE d.location IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM customers c WHERE c.city = d.location);
-- EXCEPT, emulated with LEFT JOIN ... IS NULL
SELECT DISTINCT d.location
FROM departments d
LEFT JOIN customers c ON c.city = d.location
WHERE c.id IS NULL AND d.location IS NOT NULL;The emulations are worth knowing even where the real operators exist, because they extend naturally to multi column comparisons and they let you return extra columns, which set operations cannot.
Important rules
- Column count, order and type compatibility rules are identical to
UNION. INTERSECTandEXCEPTremove duplicates unless theALLvariant is used and supported.- In standard SQL,
INTERSECTbinds tighter thanUNIONandEXCEPT. Use parentheses when mixing them. - These operations compare whole rows, so
NULLs are treated as equal to each other here - unlike in a join condition. - Set operations cannot return columns that are not being compared; a join or
EXISTScan.
Common mistakes
- Writing
INTERSECTon MySQL 5.7 or MariaDB 10.2 and getting a syntax error. - Reversing the operands of
EXCEPTand answering the opposite question. - Expecting
EXCEPTto keep duplicate rows. - Mixing
UNIONandINTERSECTwithout parentheses and relying on precedence.
Best practices
- Check the target version before using
INTERSECTorEXCEPTin shipped code. - Prefer
NOT EXISTStoEXCEPTwhen you also need columns from the first table. - Parenthesise any expression combining more than one set operator.
- Comment which question each half answers -
EXCEPTqueries are easy to read backwards.
Practice
- List product categories that appear in both
productsand in shipped order lines. - List customers who have never had a cancelled order, using
EXCEPTand again usingNOT EXISTS. - Rewrite an
INTERSECTquery for a MySQL 5.7 server.