PostgreSQLUNION, INTERSECT & EXCEPT

UNION, INTERSECT & EXCEPT

Set operations combine the results of two separate SELECT queries as if they were mathematical sets of rows. PostgreSQL supports the three standard set operations: UNION, INTERSECT, and EXCEPT.
Note
Every set operation requires both queries to return the same number of columns, with compatible data types in the same positions. Column names in the final result come from the first query.
UNION and UNION ALL
UNION combines the rows of two queries and removes duplicate rows from the combined result, just like DISTINCT does for a single query.

Every city that has either a customer or a warehouse

SQL
SELECT city FROM customers
UNION
SELECT city FROM warehouses;
UNION ALL keeps every row from both queries, including duplicates.

A combined activity feed of orders and returns, duplicates and all

SQL
SELECT order_id, 'order' AS event_type, order_date AS event_date
FROM orders
UNION ALL
SELECT return_id, 'return' AS event_type, return_date AS event_date
FROM returns;
Tip
Prefer UNION ALL whenever you already know the two queries cannot produce overlapping rows, or you simply don’t care about duplicates. UNION has to sort and de-duplicate the entire combined result, which costs extra work that UNION ALL skips entirely.
INTERSECT
INTERSECT returns only the rows that appear in both result sets.

Customers who have both placed an order and signed up for the newsletter

SQL
SELECT customer_id FROM orders
INTERSECT
SELECT customer_id FROM newsletter_subscriptions;
EXCEPT
EXCEPT returns the rows from the first query that do not appear in the second query.

Customers who have never placed an order

SQL
SELECT customer_id FROM customers
EXCEPT
SELECT customer_id FROM orders;
Note
PostgreSQL uses EXCEPT, matching the SQL standard. Oracle uses the non-standard name MINUS for the exact same operation — if you are coming from Oracle, remember to switch to EXCEPT in PostgreSQL.
  • UNION removes duplicates; UNION ALL keeps everything and is faster

  • INTERSECT returns rows common to both queries

  • EXCEPT returns rows in the first query but not the second

  • All three require the same number of columns with compatible types in both queries