INTERSECT returns selected rows common to two query results, while EXCEPT returns selected rows from the first result that are absent from the second.
A customer list and a purchaser list can be compared as sets. The overlap identifies customers with purchases; the difference identifies customers without them. These operations compare selected row values rather than joining detail records by a relationship condition.
This reference adds detail to the main course. You can read it independently: the small database below supplies every table and row used in the examples. Start with the question each query answers, then compare the returned values with the data rather than memorising a line of syntax.
Set up the practice database
Run this setup once in a new practice database, before the examples. It uses four customers and six sales. Ana has two sales, Ben has one, Cara has two, and Dev has none.
Sale 106 has no customer link; sale 104 has an unknown amount. These deliberate test cases expose missing information and unmatched relationships.
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(40) NOT NULL,
city VARCHAR(40),
manager_id INTEGER
);
CREATE TABLE sales (
id INTEGER PRIMARY KEY,
customer_id INTEGER,
amount DECIMAL(10,2),
status VARCHAR(20) NOT NULL,
created_on DATE NOT NULL
);
INSERT INTO customers (id,name,city,manager_id) VALUES
(1,'Ana','Leeds',NULL),(2,'Ben','Leeds',1),
(3,'Cara','Porto',1),(4,'Dev',NULL,2);
INSERT INTO sales (id,customer_id,amount,status,created_on) VALUES
(101,1,10,'paid','2026-01-01'),
(102,1,30,'pending','2026-01-02'),
(103,2,20,'paid','2026-01-02'),
(104,3,NULL,'pending','2026-02-01'),
(105,3,20,'paid','2026-02-02'),
(106,NULL,5,'paid','2026-02-03');An amount of zero would be a known value. The NULL amount here means the value is unknown. A customer with no matching sale differs from a sale whose customer_id is NULL.
The primary keys identify individual records even when amounts or cities repeat. Dates use year-month-day format. The examples specify sorting whenever order matters; insertion order alone does not guarantee display order.
How INTERSECT and EXCEPT works
INTERSECT computes the common selected values. Selecting customers.id and intersecting sales.customer_id produces the identified purchaser ids one, two and three. Repeated sales for the same customer do not repeat that id in the ordinary distinct result. EXCEPT is directional: customer ids EXCEPT purchaser ids returns four, while reversing the branches answers a different question about references absent from the customer list.
Both inputs must produce the same number of columns in corresponding compatible types. The selected row is the comparison unit, so selecting id and name requires the same pair on both sides. A name-only comparison can conflate two people with the same name. Use the entity identity when the question is membership of entities, and project descriptive labels afterwards through an appropriate join if needed.
Duplicates and NULL in set comparisons
Ordinary INTERSECT and EXCEPT remove duplicates and treat NULL values as equal for set comparison. This is distinct from ordinary NULL equality in WHERE. The anonymous customer_id does not remove customer four in the EXCEPT example, because NULL is a different selected value from four. This contrasts with a NOT IN predicate whose membership set includes NULL and can make the nonmatching comparison unknown.
ALL variants preserve multiplicities according to set arithmetic where supported, but support differs across engines. Compound-query precedence can also differ: INTERSECT may bind more tightly than UNION or EXCEPT. Parenthesise or use named CTE stages when combining several operations rather than relying on a reader to remember local precedence rules. Add one final ORDER BY for presentation. For a relationship with complicated eligibility conditions, a correlated EXISTS or NOT EXISTS can be easier to extend than a projected set comparison.
MySQL, PostgreSQL, SQL Server and SQLite
PostgreSQL, SQL Server and SQLite support INTERSECT and EXCEPT. MySQL added these operations in version 8.0.31; older versions require another formulation. ALL variants are not shared by every engine, so the lesson uses ordinary distinct forms. SQL Server does not support EXCEPT ALL or INTERSECT ALL.
Check the engine-specific syntax and version requirements in MySQL set operations, PostgreSQL set operations.
Practice task and worked solution
Return the identified customer ids that appear in both customers and sales. Use INTERSECT and sort the result.
Try the task before reading its worked solution. The supplied rows make the expected answer checkable by hand.
SELECT id AS customer_id FROM customers
INTERSECT SELECT customer_id FROM sales
ORDER BY customer_id;customer_id
1
2
3The common selected values are the three customer identities with sales. Their repeated occurrences in sales do not repeat the result. NULL is absent from the non-NULL customer primary-key set, so the anonymous reference is not part of the intersection.
Reverse the example’s EXCEPT branches and predict a NULL customer reference from sales rather than Dev’s id. Add WHERE customer_id IS NOT NULL to that branch and predict an empty difference, since all identified references are valid. This separates absent optional ownership from invalid parent membership and illustrates why set direction and projected fields define the question.
SQL INTERSECT and EXCEPT: Shared and Missing Set Values Syntax
INTERSECT and EXCEPT
SELECT id AS customer_id FROM customers
EXCEPT
SELECT customer_id FROM sales
ORDER BY customer_id;SQL INTERSECT and EXCEPT: Shared and Missing Set Values Summary
INTERSECTreturns rows that appear in both query results;EXCEPTreturns rows of the first result that aren't in the second.EXCEPTis directional: swapping the queries asks the opposite question.- Both remove duplicates and treat
NULLs as equal when comparing rows. - Compare identifying keys, not names, so different people with the same name aren't treated as one.
- MySQL supports both from version 8.0.31; Oracle calls
EXCEPTMINUS;EXISTSandNOT EXISTSwork everywhere.
SQL INTERSECT and EXCEPT: Shared and Missing Set Values Examples
Each example shows the code, the output it produces and what each part does.
Customers who have no sales
The first set is one, two, three and four. The second contains one, two, three and NULL after duplicate elimination. Four has no equal member in the second set and remains. The NULL does not turn this set difference into an unknown predicate.
SELECT id AS customer_id FROM customers
EXCEPT
SELECT customer_id FROM sales
ORDER BY customer_id;customer_id
4Common SQL INTERSECT and EXCEPT: Shared and Missing Set Values Mistakes
Reversing EXCEPT or comparing names
Reversing EXCEPT changes the question because set difference is not symmetric. Another mistake is comparing only customer names when customer identity is required. Shared names can make different people look equal. Select the relevant key and add labels through a later step.
SQL INTERSECT and EXCEPT: Shared and Missing Set Values in Real Projects
Comparing yesterday's and today's exports
A reconciliation can compare the ids exported yesterday with the ids required today, identifying shared, added and removed entities. Include all fields needed to define the comparison: a customer identity comparison differs from a full-row change comparison that also includes city and status.
For reconciliation, choose whether equality means the same entity or the same complete saved state. Comparing ids finds membership changes; comparing id and city can also flag a changed city as a different selected row. State that comparison contract before producing added, removed and shared sets, and keep EXCEPT direction explicit in each output label.
SQL INTERSECT and EXCEPT: Shared and Missing Set Values FAQ
Is EXCEPT the same as subtraction?
No. It is a set difference between selected rows, not numeric subtraction: it keeps the rows of the first query that don't appear in the second, and the values themselves are never subtracted.
Does INTERSECT repeat an id for every sale?
Not in the ordinary distinct form: each common row appears once, however many sales produced it. INTERSECT ALL, where supported, keeps duplicates up to the smaller count in the two inputs.
Can I use these in all MySQL versions?
No. MySQL support begins with 8.0.31, so verify the target version. On older versions, write INTERSECT as an IN or EXISTS filter and EXCEPT as NOT EXISTS or LEFT JOIN ... IS NULL.
Do INTERSECT and EXCEPT compare whole rows?
Yes. Every selected column takes part, so SELECT id, city only matches when both values are the same. Select just the columns that define "the same thing" for your question.
How can I show what changed between two tables?
Run EXCEPT both ways: A EXCEPT B lists rows that were removed or changed, and B EXCEPT A lists rows that were added or changed. Comparing on keys only, then on full rows, separates new and deleted records from edited ones.
SQL INTERSECT and EXCEPT: Shared and Missing Set Values Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Which customer id remains in customers EXCEPT sales customer links?
SQL INTERSECT and EXCEPT: Shared and Missing Set Values Quiz
2 questions to check what you learned.
Is A EXCEPT B the same as B EXCEPT A?
- No, EXCEPT is directional
- Yes, EXCEPT is a symmetric difference in both directions
- Yes, whenever both inputs select a column with the same name
Does the NULL sales reference poison the shown EXCEPT result?
- Yes, one NULL removes every first-set row
- No, set comparison has its own duplicate and equality rules
- Yes, EXCEPT has exactly the same unknown-membership behaviour as NOT IN