SQLab Hub
Lesson 39 · UNION
Lesson 39 · More Topics

SQL UNION and UNION ALL: Syntax, Differences & Examples

SQL UNION combines the results of two or more SELECT statements into one result set, stacking the rows on top of each other. UNION removes duplicate rows; UNION ALL keeps every row.

∪ UNION vs UNION ALL ▶ Runnable Playground examples 🧪 4 practice exercises 📝 5-question quiz ⏱ ~15 min

What Is SQL UNION?

The Playground database stores customers in users and staff in employees. To list every city where the company has either a customer or an employee, run one query per table and put UNION between them:

SQLite · runs in the Playground
SELECT city FROM users
UNION
SELECT city FROM employees
ORDER BY city;

▶ Run this query in the SQL Playground

Cities that appear in users or employees
city
Austin
Charlotte
Chicago
Columbus
Dallas
Denver
✓ 20 rows · first 6 shown · real output from the Playground database

The first query returns one city per customer and the second one city per employee. UNION stacks the two lists and then removes duplicates, so each city appears once: 20 rows in the result.

Use UNION when the rows you want live in more than one table (or more than one query) but have the same shape. A JOIN is the tool when you want to put related columns side by side instead.

UNION Syntax and Rules

SQL · syntax
SELECT column_1, column_2 FROM table_a
UNION [ALL]
SELECT column_1, column_2 FROM table_b
ORDER BY column_1;

Four rules apply in every database:

RuleWhat it means
Same number of columnsEvery SELECT in the UNION must return the same number of columns.
Compatible data typesColumns are matched by position, so the first column of each query should hold the same kind of value, and so on.
Names come from the first queryThe result uses the column names (or aliases) of the first SELECT.
One ORDER BY, at the endORDER BY sorts the combined result and is written once, after the last SELECT.

UNION vs UNION ALL

UNION ALL skips the duplicate check and returns every row from every query. Count the rows each version produces for the same two queries:

SQLite · runs in the Playground
SELECT 'UNION ALL' AS operator, COUNT(*) AS rows_returned
FROM (SELECT city FROM users UNION ALL SELECT city FROM employees) AS t
UNION ALL
SELECT 'UNION', COUNT(*)
FROM (SELECT city FROM users UNION SELECT city FROM employees) AS t;

▶ Run this query in the SQL Playground

Rows returned by UNION ALL and by UNION
operatorrows_returned
UNION ALL270
UNION20
✓ 2 rows · real output from the Playground database

UNION ALL returns 270 rows, one for every customer and employee. UNION returns 20, because it keeps only one copy of each city.

UNIONUNION ALL
Duplicate rowsRemovedKept
Extra workThe database must compare rows to find duplicatesNone; rows are simply appended
Use it whenYou need a list of distinct valuesThe queries cannot overlap, or you want every row (totals, logs, labelled sources)
Default to UNION ALL when duplicates are impossible or wanted. It does less work, and it never silently drops rows that happen to look the same.

Labelling Where Each Row Came From

Once rows are stacked you can no longer tell which table they came from. Add a constant column to each query to keep track:

SQLite · runs in the Playground
SELECT first_name, last_name, 'customer' AS source
FROM users
WHERE city = 'Austin'
UNION ALL
SELECT first_name, last_name, 'employee'
FROM employees
WHERE city = 'Austin'
ORDER BY source, last_name, first_name;

▶ Run this query in the SQL Playground

Customers and employees in Austin with a source label
first_namelast_namesource
SusanAndersoncustomer
StephanieDaviscustomer
CynthiaHallcustomer
DeborahJacksoncustomer
KennethSanchezcustomer
PatriciaScottcustomer
BrianTaylorcustomer
SharonWrightcustomer
KennethYoungcustomer
JamesAllenemployee
AmyNguyenemployee
JoshuaNguyenemployee
JasonRobertsemployee
✓ 13 rows · real output from the Playground database

The same pattern builds small summary reports from unrelated tables:

SQLite · runs in the Playground
SELECT 'orders' AS metric, COUNT(*) AS total FROM orders
UNION ALL
SELECT 'payments', COUNT(*) FROM payments
UNION ALL
SELECT 'reviews', COUNT(*) FROM reviews;

▶ Run this query in the SQL Playground

Row counts of three tables in one result
metrictotal
orders200
payments200
reviews180
✓ 3 rows · real output from the Playground database

UNION vs JOIN

UNIONJOIN
CombinesRows: results are stacked verticallyColumns: tables are matched side by side
NeedsThe same number and type of columnsA condition that relates the tables (ON)
Result shapeSame columns, more rowsMore columns per row
Typical question"Customers and employees in one list""Each order with its customer's name"

INTERSECT and EXCEPT

UNION has two relatives that follow the same column rules. INTERSECT returns only rows that appear in both results; EXCEPT returns rows from the first result that are not in the second. This query finds products that have never been ordered:

SQLite · runs in the Playground
SELECT id FROM products
EXCEPT
SELECT product_id FROM order_items
ORDER BY id
LIMIT 5;

▶ Run this query in the SQL Playground

Product ids with no order items
id
110
✓ 1 row · real output from the Playground database
Dialect notes. Oracle calls EXCEPT MINUS. MySQL added INTERSECT and EXCEPT in version 8.0.31; UNION and UNION ALL work in every version.

Common UNION Mistakes

Three errors that cause most UNION problems.

1. A different number of columns

❌ Two columns, then one
SQL
SELECT first_name, city FROM users
UNION
SELECT first_name FROM employees;
✅ Same columns in both
SQL
SELECT first_name, city FROM users
UNION
SELECT first_name, city FROM employees;

Every SELECT must return the same number of columns. The database stops with an error such as "SELECTs to the left and right of UNION do not have the same number of result columns".

2. ORDER BY in the middle

❌ Sorting the first query only
SQL
SELECT city FROM users ORDER BY city
UNION
SELECT city FROM employees;
✅ One ORDER BY at the end
SQL
SELECT city FROM users
UNION
SELECT city FROM employees
ORDER BY city;

ORDER BY applies to the combined result, so it belongs after the last SELECT. Most databases reject it anywhere else.

3. UNION when you need every row

❌ Duplicates removed before counting
SQL
SELECT city FROM users
UNION
SELECT city FROM employees;
✅ Every row kept
SQL
SELECT city FROM users
UNION ALL
SELECT city FROM employees;

If you plan to count or sum the combined rows, UNION quietly removes repeats and the totals come out too low. Use UNION ALL unless you specifically want distinct rows.

Practice UNION Queries

4 exercises on the real Playground tables.

Write each query yourself first. Every solution has been run against the Playground database.

  1. 1Easy List every distinct country or city name that appears as a customer country or an employee city, sorted alphabetically. Table: users, employees

    Show solution
    SQLite · runs in the Playground
    SELECT country AS place FROM users
    UNION
    SELECT city FROM employees
    ORDER BY place;

    ▶ Run this query in the SQL Playground

    UNION removes repeats, leaving 28 distinct names. The column is called place because names come from the first SELECT.

  2. 2Easy Return the email addresses of all customers and all employees in one list, keeping every row. Table: users, employees

    Show solution
    SQLite · runs in the Playground
    SELECT email FROM users
    UNION ALL
    SELECT email FROM employees;

    ▶ Run this query in the SQL Playground

    UNION ALL keeps all 270 rows: 150 customers plus 120 employees.

  3. 3Medium Show the number of cancelled orders and the number of failed payments as two labelled rows. Table: orders, payments

    Show solution
    SQLite · runs in the Playground
    SELECT 'cancelled orders' AS metric, COUNT(*) AS total
    FROM orders
    WHERE status = 'cancelled'
    UNION ALL
    SELECT 'failed payments', COUNT(*)
    FROM payments
    WHERE status = 'failed';

    ▶ Run this query in the SQL Playground

    Each SELECT produces one summary row; UNION ALL stacks them into a two-row report.

  4. 4Medium Find five customers who have never written a review, using EXCEPT. Table: users, reviews

    Show solution
    SQLite · runs in the Playground
    SELECT id FROM users
    EXCEPT
    SELECT user_id FROM reviews
    ORDER BY id
    LIMIT 5;

    ▶ Run this query in the SQL Playground

    EXCEPT keeps user ids that do not appear in reviews. A LEFT JOIN with IS NULL gives the same answer.

📝 Quiz — UNION

Test your understanding · 0/5 answered

Question 1 of 5

What is the difference between UNION and UNION ALL?

Question 2 of 5

Which rule must every query in a UNION follow?

Question 3 of 5

Where do the column names of a UNION result come from?

Question 4 of 5

Where should ORDER BY go in a UNION query?

Question 5 of 5

You want to add up rows from two tables that cannot contain the same row. Which is the better choice?

UNION Interview Questions

Q1. What is the difference between UNION and UNION ALL?

Both stack the results of two or more queries. UNION removes duplicate rows from the combined result, which requires extra comparison work. UNION ALL returns every row and is the faster choice when duplicates are impossible or wanted.

Q2. What is the difference between UNION and JOIN?

UNION combines rows: the queries must have the same columns and the results are stacked vertically. JOIN combines columns: rows from two tables are matched on a condition and placed side by side.

Q3. How would you find values that are in one table but not in another?

Use EXCEPT (MINUS in Oracle), a LEFT JOIN filtered with IS NULL, or NOT EXISTS. All three return the rows from the first set that have no match in the second.

Frequently Asked Questions

What does UNION do in SQL?

UNION combines the result sets of two or more SELECT statements into a single result and removes duplicate rows. Each SELECT must return the same number of columns with compatible data types.

Is UNION ALL faster than UNION?

Usually, yes. UNION has to compare rows to remove duplicates, while UNION ALL simply appends the results. Use UNION ALL when the queries cannot return the same row or when you want to keep duplicates.

Can I use UNION with more than two queries?

Yes. You can chain as many SELECT statements as you need, with UNION or UNION ALL between each pair. All of them must return the same number of columns.

Does UNION sort the result?

No. Some databases happen to return sorted rows as a side effect of removing duplicates, but the order is not guaranteed. Add ORDER BY after the last SELECT if the order matters.