SQL · Joins

JOINs, and why LEFT JOIN is VLOOKUP's big sibling

"How is a LEFT JOIN different from VLOOKUP?" is a favourite bridge question between the Excel and SQL rounds. You already know VLOOKUP, so we'll build from it.

Your win todayPredict, row by row, what INNER and LEFT JOIN return, including NULLs and duplicated rows, and explain the VLOOKUP comparison in two sentences.

Two tables

customers
idname
1Asha
2Ravi
3Meera
orders
order_idcustomer_idamount
1011500
1021300
1032700
1049200

Note: Meera (3) has no orders, and order 104 points to customer 9, who doesn't exist.

The join family

INNER JOINmatches only LEFT JOINall of left + matches RIGHT JOINall of right + matches FULL OUTEReverything LR
Shaded = rows kept. Where a kept row has no partner, the partner's columns come back as NULL.[PostgreSQL] (A Venn picture is a simplification. The next figure shows the thing it hides: duplicates.)

LEFT JOIN, row by row

SELECT c.name, o.order_id, o.amount
FROM   customers c
LEFT JOIN orders o ON o.customer_id = c.id;
customers (left) 1 Asha 2 Ravi 3 Meera result Asha · 101 · 500 Asha · 102 · 300 Ravi · 103 · 700 Meera · NULL · NULL 2 matches → 2 rows 0 matches → kept, NULLs Order 104 (customer 9) is dropped: it has no partner on the LEFT side. LEFT JOIN → 4 rows. INNER JOIN → 3 rows (Meera disappears).
Rule: every left row appears at least once. Once per match, or once with NULLs if there's no match.

LEFT JOIN vs VLOOKUP

VLOOKUPLEFT JOIN
Keeps every row of the main table?✅ (the formula column sits beside it)✅
No match#N/ANULL
Several matchesReturns the first one onlyReturns all of them. The row count grows.
Columns brought backOne per formulaAs many as you list in SELECT
Match on several keysNeeds a helper columnON a.x = b.x AND a.y = b.y
ScaleSlows on big sheetsBuilt for millions of rows
The trapA LEFT JOIN onto a "many" table multiplies rows. If you then SUM a column from the left table, it gets double-counted. Check the row count before and after a join.

Two handy patterns

-- Anti-join: customers who never ordered
SELECT c.name FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.order_id IS NULL;          -- → Meera

-- Filter trap: a WHERE on the right table quietly turns LEFT into INNER
LEFT JOIN orders o ON o.customer_id = c.id AND o.amount > 400   -- keeps all customers
LEFT JOIN orders o ON o.customer_id = c.id WHERE o.amount > 400 -- drops Meera (NULL > 400 is not true)
Say it in the interview"A LEFT JOIN keeps every row from the left table and attaches matching rows from the right. Where there's no match, the right-side columns are NULL. It's like VLOOKUP with two differences: VLOOKUP returns only the first match and gives #N/A, while a LEFT JOIN returns every match, so rows can multiply, and gives NULL. It can also bring back many columns and join on several keys at once."

Retrieval check

How many rows does customers INNER JOIN orders return here?

In a LEFT JOIN, what does an unmatched left row get?

A key has 3 matches. VLOOKUP returns 1 value. What does a LEFT JOIN return?

Which query finds customers with no orders?

Type it

How many rows does the LEFT JOIN above return?

Now flip it: orders LEFT JOIN customers. How many rows?

Your turn

Go deeper

Primary source: PostgreSQL Docs: Joins Between Tables. It's short and official, and it shows NULL-filled outer-join rows. For practice: StrataScratch join questions.

Related: Lesson 1: VLOOKUP · Lesson 5: GROUP BY & execution order · SQL cheat sheet

💬 Ask your teacher: "give me the CREATE TABLE script" or "what's a self join / cross join?"