00:00

MySQL UNION Operator

Last updated:

UNION combines the results of two or more SELECT statements into one result, placing rows one under another and removing duplicates. Use it when similar data lives in different tables: customers and suppliers, this year's and last year's orders, active and archived records.

1. How UNION Works

UNION stacks results and removes duplicatesThe first SELECT returns Pune, Delhi, Goa from customers. The second returns Goa, Kochi, Delhi from suppliers. UNION stacks them and removes the duplicates Delhi and Goa, giving Pune, Delhi, Goa, Kochi.SELECT city FROM customerscityPuneDelhiGoaSELECT city FROM supplierscityGoaKochiDelhiUNIONdistinct rowsresultcityPuneDelhiGoaKochiDelhi and Goa appear onceamber rows exist in both queries
Figure 1: UNION places rows of the second query under the first and removes duplicate rows.
syntax.sql
SELECT columns FROM table1
UNION [DISTINCT]
SELECT columns FROM table2
[UNION SELECT …]
[ORDER BY …] [LIMIT …];

2. A Basic UNION

query.sql
SELECT city FROM customers
UNION
SELECT city FROM suppliers;

Result: 4 rows

city
Pune
Delhi
Goa
Kochi

Delhi and Goa appear in both tables but only once in the result.

3. The Rules

  • Every SELECT must return the same number of columns.
  • Columns are matched by position, not by name; their types should be compatible.
  • Result column names come from the first SELECT.
  • Duplicates are judged on whole rows.
query.sql
SELECT name, city FROM customers
UNION
SELECT company FROM suppliers;
Output
ERROR 1222 (21000): The used SELECT statements have a different number of columns
query.sql
SELECT name AS contact, city FROM customers
UNION
SELECT company, city FROM suppliers;

Result: 6 rows

contactcity
ArnavPune
BelaDelhi
ChiragGoa
Goa SpicesGoa
Kerala CoirKochi
Delhi BrassDelhi

4. Labelling Where Rows Come From

labelled.sql
SELECT 'customer' AS type, name AS contact, email FROM customers
UNION
SELECT 'supplier', company, email FROM suppliers
ORDER BY type, contact;

Result: 6 rows

typecontactemail
customerArnavarnav@mail.example
customerBelabela@mail.example
customerChiragchirag@mail.example
supplierDelhi Brassinfo@delhibrass.example
supplierGoa Spicessales@goaspices.example
supplierKerala Coirhello@keralacoir.example

A mailing list from both tables, with a column saying which table each row came from.

5. ORDER BY and LIMIT

One ORDER BY at the end sorts the whole combined result. To sort or limit an individual SELECT, wrap it in parentheses:

per-select-limit.sql
(SELECT order_id, amount FROM orders_2025 ORDER BY amount DESC LIMIT 1)
UNION
(SELECT order_id, amount FROM orders_2026 ORDER BY amount DESC LIMIT 1)
ORDER BY amount DESC;

Result: 2 rows

order_idamount
231200
12750

The biggest order of each year.

6. Duplicates Are Removed, Sometimes Surprisingly

Customer 1 placed a ₹500 order in both years. Selecting only customer and amount makes the two rows identical, so UNION keeps one:

query.sql
SELECT customer_id, amount FROM orders_2025
UNION
SELECT customer_id, amount FROM orders_2026
ORDER BY customer_id;

Result: 5 rows

customer_idamount
1500
1300
2750
21200
3900
query.sql
SELECT SUM(amount) AS total_wrong FROM (
  SELECT customer_id, amount FROM orders_2025
  UNION
  SELECT customer_id, amount FROM orders_2026
) t;

Result: 1 row

total_wrong
3650
The total is ₹500 short. When combining facts (orders, payments), use UNION ALL, which keeps every row and is faster.

7. INTERSECT and EXCEPT (MySQL 8.0.31+)

Newer MySQL versions add the other set operations. Cities with both customers and suppliers, and cities with customers only:

query.sql
SELECT city FROM customers
INTERSECT
SELECT city FROM suppliers;

INTERSECT: in both

city
Delhi
Goa
query.sql
SELECT city FROM customers
EXCEPT
SELECT city FROM suppliers;

EXCEPT: in the first only

city
Pune

8. UNION vs JOIN

UNIONJOIN
CombinesRows (vertically)Columns (horizontally)
NeedsSame number of compatible columnsA matching condition (ON)
Result widthSame as each SELECTColumns of both tables
Typical useSame kind of data from several tablesRelated data from several tables

9. Practice Exercises

Exercise 1: List all email addresses from customers and suppliers, alphabetically.
solution.sql
SELECT email FROM customers
UNION
SELECT email FROM suppliers
ORDER BY email;

Result: 6 rows

email
arnav@mail.example
bela@mail.example
chirag@mail.example
hello@keralacoir.example
info@delhibrass.example
sales@goaspices.example
Exercise 2: Order IDs over ₹600 from either year, with the year.
solution.sql
SELECT 2025 AS yr, order_id, amount FROM orders_2025 WHERE amount > 600
UNION
SELECT 2026, order_id, amount FROM orders_2026 WHERE amount > 600
ORDER BY amount DESC;

Result: 3 rows

yrorder_idamount
2026231200
202621900
202512750

10. Summary

  • UNION stacks the results of several SELECTs and removes duplicate rows.
  • Same number of columns, matched by position; names come from the first SELECT.
  • One ORDER BY/LIMIT at the end; use parentheses for per-SELECT ordering.
  • Use UNION ALL to keep duplicates (and for speed); INTERSECT/EXCEPT exist since 8.0.31.