32 UNION, INTERSECT, EXCEPT
Set operations combine two result sets row-by-row. All three require the queries on either side to return the same number of columns with compatible types. UNION returns rows in either side (duplicates removed). INTERSECT returns rows in both. EXCEPT returns rows in the first that are not in the second. Each has an ALL variant. UNION ALL concatenates both inputs. INTERSECT ALL keeps the smaller occurrence count of each row; EXCEPT ALL subtracts the right count from the left, with a minimum of zero. The latter two still need to match and count rows.
What you’ll learn
UNIONvsUNION ALLand when each is appropriateINTERSECTandINTERSECT ALLEXCEPTandEXCEPT ALL- Combining set operations and how precedence works
- Performance: when
UNION ALLis meaningfully faster
Example
UNION deduplicates by sort or hash on the full row — that work is real and shows up in EXPLAIN. If you know the inputs cannot duplicate (because the predicates are disjoint, for example), prefer UNION ALL. On large queries the difference can be substantial.
INTERSECT and EXCEPT are less common in application code but handy for analysis: “users who clicked A and B,” “products in catalog A that are not in catalog B.”
Set operations are set-of-rows operations. The column types must align across the inputs — int and text cannot be unioned directly. Names come from the first query’s column names.
Run the example
To run (requires fruits):
Common pitfalls
UNIONinstead ofUNION ALLon queries that cannot produce duplicates wastes CPU on deduplication. PickUNION ALLunless duplicates are possible and unwanted.- Misaligned column counts or types:
SELECT id, name FROM t UNION SELECT id FROM t2is an error. Pad withNULL::textor align columns. ORDER BYafter a set operation refers to the combined result; it cannot use table-qualified column names. Use positions (ORDER BY 1) or aliases from the first query.EXCEPTis sensitive to NULL:EXCEPTtreats two NULLs as equal (likeDISTINCT), so a row with NULL on the left and NULL on the right is removed. This is usually what you want — but worth remembering.
When you find yourself writing SELECT ... WHERE x = 1 UNION ALL SELECT ... WHERE x = 2 UNION ALL ..., consider whether a single WHERE x IN (1, 2, 3) would do. Set operations are for genuinely different queries with results that need to be combined.
Write two SELECTs from fruits with different WHERE clauses and combine with UNION. Then change to UNION ALL and observe the duplicate count change (if any). Then try INTERSECT and EXCEPT between them.
Downloads
SQL file: union-intersect-except.sql · All lesson files · Setup guide