Set operations
Concept  ·  SQL & Querying

UNION removes duplicates (and pays a sort/hash); UNION ALL keeps them — correctness and cost both hinge on which.

UNION removes duplicate rows across the two inputs and pays a sort or hash to do it; UNION ALL keeps every row and skips that work. When each input row is a real event, dropping duplicates undercounts.

See it break
promo
email
a@x
b@x
newsletter
email
b@x
c@x
The trap
SELECT
  email
FROM
  promo
UNION SELECT
  email
FROM
  newsletter
ORDER BY
  email;
The fix
SELECT
  email
FROM
  promo
UNION ALL
SELECT
  email
FROM
  newsletter
ORDER BY
  email;
The trap
a@x
b@x
c@x
The fix
a@x
b@x
b@x
c@x

The 'total emails to send' count reads 3, not 4 — UNION silently merged the address that was on both lists.

The rule

Use UNION ALL when the rows are distinct events you want to keep; reach for UNION only when you actually want the duplicates removed.

SELECT ... UNION ALL SELECT ...
Shows up elsewhere
COUNT(*) vs COUNT(col) vs COUNT(DISTINCT col)
Try one →Prove it in practice →