Tier 2 · Core SQL

UNION, UNION ALL, INTERSECT, EXCEPT in SQL

By Owen Middleton · Updated September 2026 · Examples run on PostgreSQL 17

What do UNION, INTERSECT and EXCEPT do in SQL?

Set operators combine the results of two separate SELECT statements into one result set.

You're building a list of all active user IDs — some appear in the sessions table, some in the conversions table, and some in both. You could join the two tables, but this is a different kind of question: not "match rows across tables," but "stack the results of two queries together." That's what UNION ALL does. Set operators treat two complete queries as inputs and merge their output, as if both sets of rows had come from a single query.

What is the difference between UNION, UNION ALL, INTERSECT and EXCEPT?

There are four set operators. Each one combines two result sets differently:

UNION ALL stacks both result sets and keeps everything, duplicates included. UNION does the same but removes duplicate rows from the combined result. INTERSECT returns only rows that appear in both result sets. EXCEPT returns rows from the first query that don't appear in the second.

All sessions and all conversions combined:

SELECT user_id FROM sessions
UNION ALL
SELECT user_id FROM conversions

A user in both tables shows up twice. Use UNION to deduplicate:

SELECT user_id FROM sessions
UNION
SELECT user_id FROM conversions

EXCEPT finds rows in the first query with no match in the second — customers who have never placed an order:

SELECT id AS customer_id FROM customers
EXCEPT
SELECT customer_id FROM orders

INTERSECT returns rows that appear in both — users who have sessions and conversions:

SELECT user_id FROM sessions
INTERSECT
SELECT user_id FROM conversions

You can also attach a label to each row to identify its source:

SELECT user_id, 'session' AS activity_type FROM sessions
UNION ALL
SELECT user_id, 'conversion' AS activity_type FROM conversions

What are the column rules for a SQL UNION?

Both queries in a set operation must return the same number of columns, and corresponding columns must have compatible types. Column names in the output come from the first query — aliases in the second query are ignored. When types don't match exactly, use an explicit cast: id::text converts an integer to text so it can stack with a text column.

Does the order of queries matter in EXCEPT?

EXCEPT is directional. The order of the two queries determines the result. A EXCEPT B returns rows in A with no match in B. Swap them and you get rows in B with no match in A — a valid result that answers a different question. A logic error here produces output that looks plausible.

How do you sort the result of a UNION?

ORDER BY applies to the final combined result, not to either individual query. You can't sort one input before the set operation and expect that order to survive. Put ORDER BY after the last query to sort the whole combined result.

Should you use UNION or UNION ALL?

The one thing that trips people up: using UNION when you should use UNION ALL.

UNION deduplicates by sorting or hashing the entire combined result set. On large tables that's a real cost. Default to UNION ALL and switch to UNION only when you specifically need deduplication — for example, when combining two sets that may have overlapping rows and you want each row once.

Practice UNION in SQL

Practice · easy analytics · Streamhub

Streamhub's growth team wants to gather every user ID that appears in either session records or conversion records into a single list for batch processing. Duplicates must be preserved — a user with three sessions and two conversions should produce five rows.

Write a query to return the combined list of user IDs.

Assumptions:

  • The sessions table records each session; user_id identifies the user.
  • The conversions table records each paid conversion; user_id identifies the user.
  • The output should not deduplicate — every record from both tables contributes one row.

Output:

  • One row per source record across both tables, with a single column user_id.
Schema · analytics5 tables? = nullable
users
idinteger
nametext
emailtext
countrytext
plantext
signed_up_attimestamptz
is_activeboolean
conversions
idinteger
user_id?integer
converted_attimestamptz
plantext
amountnumeric
sessions
idinteger
user_id?integer
started_attimestamptz
ended_at?timestamptz
event_countinteger
events
idinteger
user_id?integer
session_id?integer
event_typetext
occurred_attimestamptz
properties?jsonb
periods
idinteger
nametext
start_monthinteger
end_monthinteger

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution

The full breakdown walks through the shape, each clause, why this approach beats the alternatives, and the trap to avoid.

See the full worked solution

9 UNION practice problems

Start learning to practice all 9 UNION problems, with instant grading and mastery tracking.

Common questions about UNION

Does UNION remove duplicates inside a single query too?

Yes. UNION deduplicates the whole combined result, so a value repeated twice within the first query still appears once at the end. If you only meant to stack the two results and keep everything, UNION ALL is the one that does that.

Can you combine more than two queries?

Yes. Chain as many as you need with the same operator between each pair. With UNION the deduplication still applies across the whole chain rather than to each pair in turn.

What happens if the two queries have different numbers of columns?

The statement is rejected before it runs, saying each query must have the same number of columns. Types have to line up as well, position by position, which is why an explicit cast is sometimes needed to stack an id against a text column.

Does UNION return rows in a predictable order?

No. Deduplicating may leave the output looking sorted, but nothing guarantees it. Put ORDER BY after the final query when the order matters, and it applies to the whole combined result rather than to either part.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.