PostgreSQL Set Operations

Set operations combine the results of two SELECT queries into one result. JOINs place tables side by side, adding columns. Set operations stack results on top of each other, adding rows.

  Query A rows
  ------------
  Query B rows
  ------------
  = One combined result

Imagine two class attendance sheets. One lists students who joined the art club. The other lists students who joined the music club. Set operations answer questions such as "Who joined at least one club?" and "Who joined both?"

Before You Start

Two rules and one small data set prepare every example on this page.

Rules for Combining Queries

  • Both queries must return the same number of columns.
  • Matching columns must have compatible data types.
  • Column names in the final result come from the first query.

Sample Data

art_clubmusic_club
AshaRavi
RaviMina
TaraAsha
CREATE TABLE art_club   (name TEXT);
CREATE TABLE music_club (name TEXT);

INSERT INTO art_club   VALUES ('Asha'), ('Ravi'), ('Tara');
INSERT INTO music_club VALUES ('Ravi'), ('Mina'), ('Asha');

The Four Operators

Each operator answers a different question about two lists.

UNION

UNION merges both results and removes duplicate rows. The output lists every student who joined at least one club.

SELECT name FROM art_club
UNION
SELECT name FROM music_club;

Result: Asha, Ravi, Tara, Mina. Asha and Ravi appear once each.

  (Asha Ravi Tara)  U  (Ravi Mina Asha)
        = Asha Ravi Tara Mina

UNION ALL

UNION ALL keeps every row, including duplicates. It runs faster, because the database skips the duplicate check.

SELECT name FROM art_club
UNION ALL
SELECT name FROM music_club;

Result: Asha, Ravi, Tara, Ravi, Mina, Asha. Six rows appear. Choose UNION ALL when you know duplicates cannot exist or when you want to count them.

INTERSECT

INTERSECT returns only rows that appear in both results. The output lists students who joined both clubs.

SELECT name FROM art_club
INTERSECT
SELECT name FROM music_club;

Result: Asha and Ravi.

   Art       Music
  ( Tara ( Asha  ) Mina )
         ( Ravi  )
        overlap only

EXCEPT

EXCEPT returns rows from the first query that the second query does not contain. The output lists students who joined art but skipped music.

SELECT name FROM art_club
EXCEPT
SELECT name FROM music_club;

Result: Tara. Order matters here. Swap the two queries, and the answer becomes Mina.

Comparison at a Glance

OperatorQuestion It AnswersDuplicates
UNIONWho appears in either list?Removed
UNION ALLGive me everything from both listsKept
INTERSECTWho appears in both lists?Removed
EXCEPTWho appears only in the first list?Removed

Tips and Uses

Sorting, labels, and real tasks show how the operators work in practice.

Sorting a Combined Result

Place one ORDER BY at the very end. It sorts the full combined result.

SELECT name FROM art_club
UNION
SELECT name FROM music_club
ORDER BY name;

Adding a Label Column

Track where each row came from by adding a fixed text column to each query.

SELECT name, 'Art' AS club FROM art_club
UNION ALL
SELECT name, 'Music' AS club FROM music_club;

Real-World Uses

  • Merge yearly sales tables such as sales_2024 and sales_2025 into one report.
  • Find customers who bought online but never visited a store, using EXCEPT.
  • Find products sold in two regions at once, using INTERSECT.