Module 3: Working with Multiple Tables40 min

Combining Results with UNION

Progress Tracking

Log in to save this lesson and continue from where you left off.

Log in

Stacking Results, Not Joining

Before we learn how to link tables side by side, there’s another way to combine data from multiple tables: UNION.

UNION doesn’t “link” rows together. Instead, it stacks results on top of each other. Think of UNION as “add more rows to the same shape of table.”

Later, when we talk about JOINs, we’ll see the opposite pattern:

  • JOINs add more columns about each row
  • UNION adds more rows with the same columns

For now, keep one idea in your head: UNION = same columns, more rows.

When You’ll Use UNION

UNION comes up when you have data split across tables that should really be together:

  • Separate tables for different regions (us_orders, eu_orders)
  • Historical data in yearly tables (orders_2022, orders_2023)
  • Different data sources with the same structure (app_signups, web_signups)
  • Building a lookup list from multiple places

Basic UNION Syntax

SQL
SELECT column1, column2
FROM table_a

UNION

SELECT column1, column2
FROM table_b;

Simple: two SELECT statements with UNION between them. The results stack on top of each other.

A Real Example

Say you need all employees from HR and Admin in one list.

Table: techcorp_workforce
idfirst_namelast_namedepartmentsalaryphone_numberjoining_date
1SarahMitchellHR95000555-01012021-03-15
2MichaelChenHR88000555-01022022-06-01
3EmilyRodriguezHR825002021-09-20
4DavidParkHR80000555-01042023-01-10
5LisaThompsonHR650002021-04-05
1
Try UNION with Source Labels

Combine HR and Admin employees into one list using UNION. Add a type column with 'Employee' for HR and 'Admin' for Admin staff.

Tables: techcorp_workforce

Notice the added type column. That’s a common pattern when you’re combining tables: add a source identifier so you know where each row came from.

Make the Friends Network Symmetric

Table: google_friends_network
user_idfriend_id
01
02
03
04
15
2
Make the friends network symmetric
View solution

Make the friends network symmetric. For example, if 0 and 1 are friends, have the output contain both 0 and 1 under 1 and 0 respectively.

Tables: google_friends_network

The Column Matching Rule

UNION has a strict requirement: both SELECTs must return the same number of columns, and the data types must be compatible.

SQL
-- This works: both have 2 columns (text, text)
SELECT name, email
FROM employees

UNION

SELECT name, email
FROM contractors;

-- This FAILS: different number of columns
SELECT name, email, salary
FROM employees

UNION

SELECT name, email
FROM contractors; -- Error!

If one table has more columns than you need, just don’t select them. If one table is missing a column, you can add a placeholder:

SQL
SELECT name, email, salary
FROM employees

UNION

SELECT name, email, NULL AS salary
FROM contractors;
Column names come from the first SELECT

Column names in the result come from the first SELECT. The second SELECT’s column names are ignored.

All Possible Wine Varieties

Table: winemag_p1
idcountrydescriptiondesignationpointspriceprovinceregion_1region_2varietywinery
126576USRich and round, this offers plenty of concentrated blackberry notes enveloped in warm spices and supple oak. There's a hint of green tomato leaves throughout, but the lush fruit combined with sturdy grape tannins and high acidity would pair well with fatty short ribs or braised pork.Estate Club8732VirginiaVirginiaMerlotVeramar
127077ItalyThis luminous sparkler offers measured aromas of yellow fruit and honey and delivers a broad, wide approach in the mouth. The wine's texture is creamy and full and there is a spicy point of effervescence on the palate.Extra Dry8519VenetoProsecco di ValdobbiadeneProseccoVaraschin
143029USThere are some pretty features to this wine, namely the lovely tannins and rich fruit, but it's just too soft and sweet. Tastes like blackberry jam, with extra white sugar spinkled on top.Signature8345CaliforniaPaso RoblesCentral CoastCabernet SauvignonByington
98813USLovely nose, which runs from violets and cherries right into coffee and sweet chocolate. In the mouth the wine coats the palate with Napa-like intensity, only buttressed with more vivid acidity. It's both smooth and deep. The aromas are more detailed, interesting and really clean, loaded with dark flavors of soy, coffee, molasses and black cherry liqueur.Champoux & Loess Vineyards Reserve93100WashingtonWashingtonWashington OtherCabernet SauvignonBoudreaux Cellars
43172USTastes sweeter and fruitier than the 2009, which was dry, so if you like orange marmalade, pineapple tart and vanilla cookie sugariness in your Sauvignon Blancs, it's for you.Les Pionniers8640CaliforniaSonoma CountySonomaSauvignon BlancCapture
Table: winemag_p2
idcountrydescriptiondesignationpointspriceprovinceregion_1region_2taster_nametaster_twitter_handletitlevarietywinery
118040USA bit too soft and thus lacks structure. Shows a good array of wild berry and briary, brambly flavors. Dry and spicy, and ready now.The Convict Rocky Ridge Vineyard8638CaliforniaRockpileSonomaParadise Ridge 2006 The Convict Rocky Ridge Vineyard Zinfandel (Rockpile)ZinfandelParadise Ridge
59743ItalyAromas of toasted oak, vanilla and a confectionary note lead the nose while the palate offers mature Golden Delicious apple, butterscotch and walnut skin alongside bracing acidity.Mongris Riserva8830Northeastern ItalyCollioKerin O'Keefe@kerinokeefeMarco Felluga 2012 Mongris Riserva Pinot Grigio (Collio)Pinot GrigioMarco Felluga
117951USHeavy in alcohol and overripe, but entirely dry, and the black currant, chocolate and pepper flavors will play well against richly sauced barbecue.The Caboose8430CaliforniaAlexander ValleySonomaStarry Night 2007 The Caboose Zinfandel (Alexander Valley)ZinfandelStarry Night
10202FranceFragrant; dusty plum and rose aromas are followed on the palate by very fruity flavors of cherries and apple skins. The fine bead and rich mousse result in a creamy mouthfeel. It's all a bit obvious and simple, but undeniably good.Brut Rosa8783ChampagneChampagneJoe Czerwinski@JoeCzRuinart NV Brut Rosa (Champagne)Champagne BlendRuinart
69268GermanyLayers of plush yellow peach and apricot flavors highlight this easy, crowd-pleasing kabinett. Sunny lemon acidity lends refreshment to the midpalate, cutting through all the ripeness and leading to a brisk finish. Drink now through 2019.Kabinett8815RheinhessenAnna Lee C. IijimaWeinreich 2012 Kabinett Riesling (Rheinhessen)RieslingWeinreich
3
Find all possible varieties which occur in either of the winemag datasets
View solution

Find all possible varieties which occur in either of the winemag datasets. Output unique variety values only. Sort records based on the variety in ascending order.

Tables: winemag_p1, winemag_p2

UNION vs UNION ALL

  • UNION removes duplicate rows (expensive)
  • UNION ALL keeps everything (fast)
Table: techcorp_workforce
idfirst_namelast_namedepartmentsalaryphone_numberjoining_date
1SarahMitchellHR95000555-01012021-03-15
2MichaelChenHR88000555-01022022-06-01
3EmilyRodriguezHR825002021-09-20
4DavidParkHR80000555-01042023-01-10
5LisaThompsonHR650002021-04-05
4
Try UNION ALL

Stack the same HR department query twice using UNION ALL. How many rows appear?

Tables: techcorp_workforce

In practice, UNION ALL is what you want 90% of the time. Duplicates usually matter — they represent real data. If John ordered from both the US and EU sites, you want both orders in your analysis.

Default to UNION ALL

Use UNION ALL unless you specifically need deduplication. It’s faster, and keeping duplicates is usually correct.

Duplicate HR Department Employees

Table: worker
worker_idfirst_namelast_namesalaryjoining_datedepartment
1MonikaArora1000002014-02-20HR
2NiharikaVerma800002014-06-11Admin
3VishalSinghal3000002014-02-20HR
4AmitahSingh5000002014-02-20Admin
5VivekBhati5000002014-06-11Admin
5
Duplicate HR Department Employees
View solution

Generate a list of employees who work in the HR department, including only their first names and department in the output. Each employee should appear twice in the list, meaning their first name and department should be duplicated in the output.

Tables: worker

Sorting UNION Results

ORDER BY goes at the very end, after all the UNIONs:

SQL
SELECT name, signup_date
FROM web_users

UNION ALL

SELECT name, signup_date
FROM app_users
ORDER BY signup_date DESC;

You can’t ORDER BY in the middle. SQL processes all the UNIONs first, then sorts the combined result.

ORDER BY dialect differences

SQL Server is strict: you can only ORDER BY column names that appear in the output, or by position (ORDER BY 1, 2). PostgreSQL and MySQL are more lenient.

Pattern 1: Multi-Region Data

SQL
SELECT
  order_id,
  customer_id,
  amount,
  'US' AS region
FROM us_orders

UNION ALL

SELECT
  order_id,
  customer_id,
  amount,
  'EU' AS region
FROM eu_orders

UNION ALL

SELECT
  order_id,
  customer_id,
  amount,
  'APAC' AS region
FROM apac_orders;

Pattern 2: Creating a Reference List

SQL
-- Build a list of all people we might need to contact
SELECT email
FROM customers

UNION

SELECT email
FROM newsletter_subscribers

UNION

SELECT email
FROM lead_forms;

Here UNION (not ALL) makes sense because you only want each email once.

Table: transportation_numbers
indexnumber
15
23
37
41
50
6
Try UNION vs UNION ALL

Stack two non-overlapping subsets of transportation_numbers. Does it matter whether you use UNION or UNION ALL here?

Tables: transportation_numbers

Key Takeaways

  • UNION stacks rows vertically (vs JOIN, which combines columns horizontally)
  • Both SELECTs must have the same number of columns with compatible types
  • UNION removes duplicates, UNION ALL keeps them (prefer UNION ALL)
  • ORDER BY goes at the end, applying to the combined result
  • Add a source column to track where each row came from

What’s Next

Now you know how to stack data from similar tables. But most of the time, you need to combine related data from different tables — customers with their orders, products with their categories. That’s where JOINs come in, starting with INNER JOIN.