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.
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:
SELECT city FROM users
UNION
SELECT city FROM employees
ORDER BY city;
▶ Run this query in the SQL Playground
| city |
|---|
| Austin |
| Charlotte |
| Chicago |
| Columbus |
| Dallas |
| Denver |
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
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:
| Rule | What it means |
|---|---|
| Same number of columns | Every SELECT in the UNION must return the same number of columns. |
| Compatible data types | Columns 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 query | The result uses the column names (or aliases) of the first SELECT. |
| One ORDER BY, at the end | ORDER 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:
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
| operator | rows_returned |
|---|---|
| UNION ALL | 270 |
| UNION | 20 |
UNION ALL returns 270 rows, one for every customer and employee. UNION returns 20, because it keeps only one copy of each city.
| UNION | UNION ALL | |
|---|---|---|
| Duplicate rows | Removed | Kept |
| Extra work | The database must compare rows to find duplicates | None; rows are simply appended |
| Use it when | You need a list of distinct values | The queries cannot overlap, or you want every row (totals, logs, labelled sources) |
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:
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
| first_name | last_name | source |
|---|---|---|
| Susan | Anderson | customer |
| Stephanie | Davis | customer |
| Cynthia | Hall | customer |
| Deborah | Jackson | customer |
| Kenneth | Sanchez | customer |
| Patricia | Scott | customer |
| Brian | Taylor | customer |
| Sharon | Wright | customer |
| Kenneth | Young | customer |
| James | Allen | employee |
| Amy | Nguyen | employee |
| Joshua | Nguyen | employee |
| Jason | Roberts | employee |
The same pattern builds small summary reports from unrelated tables:
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
| metric | total |
|---|---|
| orders | 200 |
| payments | 200 |
| reviews | 180 |
UNION vs JOIN
| UNION | JOIN | |
|---|---|---|
| Combines | Rows: results are stacked vertically | Columns: tables are matched side by side |
| Needs | The same number and type of columns | A condition that relates the tables (ON) |
| Result shape | Same columns, more rows | More 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:
SELECT id FROM products
EXCEPT
SELECT product_id FROM order_items
ORDER BY id
LIMIT 5;
▶ Run this query in the SQL Playground
| id |
|---|
| 110 |
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
SELECT first_name, city FROM users
UNION
SELECT first_name FROM employees;
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
SELECT city FROM users ORDER BY city
UNION
SELECT city FROM employees;
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
SELECT city FROM users
UNION
SELECT city FROM employees;
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.
-
1Easy List every distinct country or city name that appears as a customer country or an employee city, sorted alphabetically. Table:
users, employeesShow solution
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
placebecause names come from the first SELECT. -
2Easy Return the email addresses of all customers and all employees in one list, keeping every row. Table:
users, employeesShow solution
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.
-
3Medium Show the number of cancelled orders and the number of failed payments as two labelled rows. Table:
orders, paymentsShow solution
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.
-
4Medium Find five customers who have never written a review, using EXCEPT. Table:
users, reviewsShow solution
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
What is the difference between UNION and UNION ALL?
UNION removes duplicate rows from the combined result. UNION ALL appends every row as it is.
Which rule must every query in a UNION follow?
Columns are matched by position, so each SELECT must return the same number of columns with compatible types.
Where do the column names of a UNION result come from?
The result takes its column names or aliases from the first SELECT.
Where should ORDER BY go in a UNION query?
ORDER BY sorts the combined result, so it is written once at the very end.
You want to add up rows from two tables that cannot contain the same row. Which is the better choice?
With no possible duplicates, UNION ALL gives the same rows as UNION without the cost of checking for duplicates.
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.