EXCEPT

Find rows in the first result that don't appear in the second

Advanced 8 minEXCEPTset operationsMINUS

Set Difference

EXCEPT returns rows from the first query that do not appear in the second query — the set-theory difference: A minus B. It answers "what's in the first set but not the second?" Here's what to know:

Direction matters — A EXCEPT B is not the same as B EXCEPT A. The first query is always the source set, and the second query defines what gets excluded from it. Swapping them produces completely different results.
Alternative to anti-joins — EXCEPT replaces the LEFT JOIN + WHERE right.id IS NULL pattern for finding "what exists in A but not in B." It's cleaner, more readable, and conveys the intent more directly in your query.
Auto-deduplicates — Like UNION and INTERSECT, EXCEPT automatically removes duplicate rows from the final result. Some databases use the keyword MINUS instead of EXCEPT — Oracle is the most notable example.
Knowledge Canvas

How EXCEPT Works

Find rows in A but not in B

  • A EXCEPT B = rows in first query NOT in second
  • Direction matters: A EXCEPT B ≠ B EXCEPT A
  • Auto-deduplicates like UNION and INTERSECT
  • Oracle uses MINUS instead of EXCEPT

EXCEPT vs Anti-Join

Two ways to find what's missing

EXCEPT: set difference, concise
LEFT JOIN + IS NULL: more flexible
Compares full rows
Match on specific columns
Auto-deduplicates
Preserves duplicates from left

EXCEPT Gotchas

Direction and dedup

  • Swapping query order gives completely different results
  • EXCEPT auto-deduplicates — duplicates in A are collapsed
  • Column count mismatch → syntax error
  • Not available in older MySQL versions (pre-8.0)

When to Use EXCEPT

Finding gaps and differences

  • Customers who ordered but never reviewed
  • Products not in any order
  • Data reconciliation between systems
  • Regression testing: old results EXCEPT new results
Syntax
Syntax Template
1SELECT
2 cols
3FROM table_a
4EXCEPT
5SELECT
6 cols
7FROM table_b;
EXCEPTRows in first query but NOT in second
Direction mattersA EXCEPT B ≠ B EXCEPT A
Sample Data
orders
12 rows
idcustomer_id
5001C1001
5002C1002
5003C1001
5004C1003
5005C1006
5006C1005
5007C1004
5008C1009
5009C1012
5010C1007
5011C1008
5012C1010
reviews
12 rows
idcustomer_idproduct_id
7001C1001P101
7002C1003P101
7003C1005P101
7004C1002P102
7005C1006P102
7006C1004P103
7007C1007P104
7008C1009P105
7009C1012P105
7010C1008P107
7011C1011P108
7012C1001P109
order_items
16 rows
idorder_idproduct_idquantityunit_price
60015001P101224.99
60025001P104112.99
60035002P1092159
60045002P1021189
60055003P10818.5
60065004P107189.99
60075005P106195
60085005P1021189
60095006P1091159
60105007P103145.5
60115008P105179
60125009P1101425
60135010P101124.99
60145011P105179
60155011P103145.5
60165012P107189.99

Worked Example

Find customer IDs that placed orders but never left a review.

SQL
1SELECT DISTINCT
2 customer_id
3FROM orders
4EXCEPT
5SELECT DISTINCT
6 customer_id
7FROM reviews;
All unique customer_ids from orders are computed. Then any that also appear in reviews are removed. What remains are customers who ordered but never reviewed.
Output
1 row
customer_id
C1010
Common Mistakes

Column count mismatch

SQL
1SELECT
2 name,
3 email
4FROM customers
5EXCEPT
6SELECT
7 name
8FROM products;

First query has 2 columns, second has 1. Set operations require matching column counts.

Ensure both SELECTs have the same number of columns with compatible types.

Key Concepts

1A EXCEPT B ≠ B EXCEPT A — direction matters
2Cleaner than LEFT JOIN + WHERE IS NULL for finding gaps
3Auto-deduplicates like UNION and INTERSECT
4Some databases call it MINUS instead of EXCEPT (Oracle)

Pro Tip

Finding what's missing or different between two datasets is a fundamental analysis task. EXCEPT expresses it naturally.

When to Use

Customers who ordered but never reviewed, products not in any order, data reconciliation between systems.

Challenge

Solve the problem below

Find product IDs that have been ordered but never reviewed. Use EXCEPT on the product_id columns from order_items and reviews.

Your Query