SQL UNION vs UNION ALL: Duplicates, Types and Ordering

UNION combines compatible query results and removes duplicate selected rows, while UNION ALL preserves every row from each branch.

Lesson 65 of 102Intermediate10 min read

UNION combines compatible query results and removes duplicate selected rows, while UNION ALL preserves every row from each branch.

Combining two lists is different from joining their records side by side. UNION stacks result rows vertically. Choose whether equal selected rows represent duplicates to remove or separate observations that must be retained.

This reference adds detail to the main course. You can read it independently: the small database below supplies every table and row used in the examples. Start with the question each query answers, then compare the returned values with the data rather than memorising a line of syntax.

Set up the practice database

Run this setup once in a new practice database, before the examples. It uses four customers and six sales. Ana has two sales, Ben has one, Cara has two, and Dev has none.

Sale 106 has no customer link; sale 104 has an unknown amount. These deliberate test cases expose missing information and unmatched relationships.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name VARCHAR(40) NOT NULL,
  city VARCHAR(40),
  manager_id INTEGER
);
CREATE TABLE sales (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER,
  amount DECIMAL(10,2),
  status VARCHAR(20) NOT NULL,
  created_on DATE NOT NULL
);
INSERT INTO customers (id,name,city,manager_id) VALUES
  (1,'Ana','Leeds',NULL),(2,'Ben','Leeds',1),
  (3,'Cara','Porto',1),(4,'Dev',NULL,2);
INSERT INTO sales (id,customer_id,amount,status,created_on) VALUES
  (101,1,10,'paid','2026-01-01'),
  (102,1,30,'pending','2026-01-02'),
  (103,2,20,'paid','2026-01-02'),
  (104,3,NULL,'pending','2026-02-01'),
  (105,3,20,'paid','2026-02-02'),
  (106,NULL,5,'paid','2026-02-03');

An amount of zero would be a known value. The NULL amount here means the value is unknown. A customer with no matching sale differs from a sale whose customer_id is NULL.

The primary keys identify individual records even when amounts or cities repeat. Dates use year-month-day format. The examples specify sorting whenever order matters; insertion order alone does not guarantee display order.

How UNION vs UNION ALL works

Both branches must return the same number of columns with compatible types in corresponding positions. Column names need not match, because the mapping is positional; the combined output names normally come from the first query. Give the first branch useful aliases. A mismatched numeric and text position may cause an error or an implicit conversion whose behaviour depends on the engine.

UNION performs duplicate elimination across the complete selected row, including repeats within either branch. UNION ALL retains those repeats. If one list contains Leeds twice and another contains Porto once, UNION returns Leeds and Porto while UNION ALL retains both Leeds observations. Adding a source label can make two otherwise equal rows distinct, because that label becomes part of the selected combination.

NULL and duplicates in set operations

NULL values are treated as equal for set-operation duplicate elimination, unlike ordinary equality comparison. Selecting unknown city twice with UNION produces one unknown result row. This is a result-set operation rather than a claim that NULL = NULL is true in a WHERE predicate. Text collation and type resolution also influence what is considered the same selected value.

Apply the final ORDER BY to the combined result, usually through an output column name or an outer query. A branch’s apparent order is not a promise about final order. Branch-local limits and ordering require dialect-specific parenthesisation or derived tables. UNION can incur a deduplication cost, while UNION ALL avoids that work when all observations should be retained. Choose according to meaning rather than automatically using the supposedly faster form; dropping legitimate repeated transactions changes totals.

MySQL, PostgreSQL, SQL Server and SQLite

UNION and UNION ALL are supported by all four systems. Type coercion, collations and branch-order syntax differ, so keep compatible expressions and use an outer query for complicated ordering. SQL Server set operations may resolve types according to its type-precedence rules, while SQLite compound SELECT has its own comparison and affinity rules.

Check the engine-specific syntax and version requirements in PostgreSQL UNION operations.

Practice task and worked solution

Combine the same known city list with an extra Leeds using UNION ALL and count how many occurrences the combined input contains.

Try the task before reading its worked solution. The supplied rows make the expected answer checkable by hand.

SQL
SELECT COUNT(*) AS city_occurrences FROM (
 SELECT city FROM customers WHERE city IS NOT NULL
 UNION ALL SELECT 'Leeds' AS city
) AS combined;
Output
city_occurrences
4

The customer branch contributes three rows: two Leeds and one Porto. The literal branch contributes a fourth Leeds occurrence. UNION ALL preserves all four, and the outer count measures occurrences rather than the two distinct city labels.

Add a source-label column to both city branches and observe how the full-row comparison changes duplicate removal. Leeds from customers and Leeds from a literal branch can now remain separate because their labels differ. Remove the source label and switch between UNION and UNION ALL, counting two unique labels versus four city occurrences in the supplied example.

SQL UNION vs UNION ALL: Duplicates, Types and Ordering Syntax

UNION vs UNION ALL

SELECT city FROM customers WHERE city IS NOT NULL
UNION
SELECT 'Leeds' AS city
ORDER BY city;

SQL UNION vs UNION ALL: Duplicates, Types and Ordering Summary

  • UNION stacks the results of two queries and removes duplicate rows; UNION ALL keeps every row.
  • Both queries need the same number of columns with compatible types; names come from the first query.
  • Duplicate removal compares whole rows and treats NULLs as equal, unlike = in a WHERE clause.
  • Use one ORDER BY at the end to sort the combined result.
  • UNION ALL is faster and is correct whenever every row is a separate event you want to keep.

SQL UNION vs UNION ALL: Duplicates, Types and Ordering Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A combined, duplicate-free city list

The first branch has Leeds twice and Porto once. The second branch adds another Leeds. UNION removes equal selected city rows and yields the two labels in the explicit final order.

SQL
SELECT city FROM customers WHERE city IS NOT NULL
UNION
SELECT 'Leeds' AS city
ORDER BY city;
Output
city
Leeds
Porto

Common SQL UNION vs UNION ALL: Duplicates, Types and Ordering Mistakes

UNION collapsing separate transactions

Using UNION for transaction rows that select only amount can collapse two different sales of twenty into one row. Select the transaction identity if it is relevant, or use UNION ALL when every occurrence is intended. Conversely, UNION ALL in a label list can expose repeated labels that should be shown once.

SQL UNION vs UNION ALL: Duplicates, Types and Ordering in Real Projects

Combining archived and current transactions

A report combining archived and current transactions usually needs UNION ALL if the sources contain separate events. If their periods overlap, solve the overlap through a reliable identity or boundary rule. A city filter list instead needs duplicate-free labels, so UNION or DISTINCT expresses a different purpose.

Check overlap between current and archive sources before combining transactions. UNION ALL preserves occurrences, while UNION compares only the selected row fields and can collapse genuinely different events. A stable event identity and explicit period boundary are better controls for overlapping feeds than deduplicating a monetary amount or a customer name.

SQL UNION vs UNION ALL: Duplicates, Types and Ordering FAQ

Does UNION put columns beside each other?

No. It stacks rows, so the result has the same columns and more rows. A JOIN combines related rows side by side, giving more columns.

Is UNION ALL always correct for reports?

Only if every branch row is a legitimate retained observation. If the sources overlap, such as an archive and a live table that both contain last month, UNION ALL double counts; resolve the overlap with a reliable identity or a date boundary.

Does UNION remove rows based on one column?

No. It compares the full selected row, so adding a column, such as a sale id, can make rows that looked duplicate distinct again. Choose the selected columns to match what "the same row" should mean.

How do I tell which branch a row came from?

Add a literal label column to each branch: SELECT 'current' AS source, id, amount FROM sales UNION ALL SELECT 'archive', id, amount FROM sales_archive. The label also stops UNION from merging identical rows that came from different sources.

Can I use LIMIT in each branch of a UNION?

Yes, by wrapping each branch in brackets or a subquery, such as (SELECT ... ORDER BY amount DESC LIMIT 3) UNION ALL (SELECT ...) in PostgreSQL and MySQL. SQLite needs each branch as a subquery in FROM. A final ORDER BY and LIMIT outside apply to the combined result.

SQL UNION vs UNION ALL: Duplicates, Types and Ordering Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choicemedium

How many occurrences does the UNION ALL city-count exercise retain?

SQL UNION vs UNION ALL: Duplicates, Types and Ordering Quiz

2 questions to check what you learned.

  1. Which operation preserves repeated selected rows?

    • UNION without ALL
    • SELECT DISTINCT over the combined selected rows
    • UNION ALL
  2. How do columns correspond between union branches?

    • By position with compatible types
    • By automatic matching of each branch’s column aliases
    • By alphabetical column names instead of selected expression order