Session 05 · Phase 1: Foundations & SQL

SQL Joins — All Types & Multi-Table

Joins are the most-tested topic in any SQL interview. They combine data from multiple tables — and reveal whether you think in sets or guess at syntax.

⏱ ~2 hrs 📚 Core content 🎯 Highest priority

Learning Objectives

0. The Sample Tables

Joins need at least two related tables. We use customerstransactions (from earlier), plus a new employees table for self joins.

customer_idcustomer_namecityaccount_typebalance
1Aarav SharmaMumbaiSavings25000
2Priya VermaDelhiCurrent120000
3Rahul MehtaMumbaiSavings8000
4Sneha IyerBengaluruSalary95000
5Vikram SinghDelhiCurrent45000
6Ananya DasChennaiSavings15000
txn_idcustomer_idamount
1011500
10211200
1032800
1043300
1051950
10641500
emp_idemp_namemanager_iddept
1Aarav MehtaNULLLeadership
2Priya Rao1Finance
3Rahul Shah1Marketing
4Sneha Iyer2Finance
5Vikram Das2Finance
📝
Note: A join connects tables on a related column. Here, customers.customer_idtransactions.customer_id is the relationship (a foreign key).

1. INNER JOIN — Only Matching Rows

INNER JOIN returns only rows where there's a match in both tables. Rows without a match on either side are dropped.

-- Customers who have at least one transaction
SELECT c.customer_name, t.amount
FROM customers c
INNER JOIN transactions t
    ON c.customer_id = t.customer_id;

Customers 5 and 6 have no transactions, so they don't appear. Customer 1 appears three times (once per transaction).

📝
Follow-up interview question: "How many rows does INNER JOIN return if nothing matches?" — Zero. No match means no output row.

2. LEFT JOIN — Keep All Left Rows

LEFT JOIN keeps all rows from the left (first) table, and matches from the right table where possible. Unmatched right columns become NULL.

-- ALL customers, with their transactions (NULL if none)
SELECT c.customer_name, t.amount
FROM customers c
LEFT JOIN transactions t
    ON c.customer_id = t.customer_id;

Now customers 5 and 6 appear with NULL amounts — because we kept the entire left table.

🌐
Real World: LEFT JOIN is the workhorse join in reporting — "show me all customers and their orders, even if some haven't ordered yet."

3. RIGHT JOIN and FULL OUTER JOIN

RIGHT JOIN — mirror of LEFT JOIN

Keeps all rows from the right table. Any RIGHT JOIN can be rewritten as a LEFT JOIN by swapping the tables.

-- These two are identical:
SELECT c.customer_name, t.amount
FROM customers c
RIGHT JOIN transactions t ON c.customer_id = t.customer_id;

SELECT c.customer_name, t.amount
FROM transactions t
LEFT JOIN customers c ON t.customer_id = c.customer_id;

FULL OUTER JOIN — keep everything from both sides

Returns all rows from both tables, matching where possible and filling with NULL where not.

SELECT c.customer_name, t.amount
FROM customers c
FULL OUTER JOIN transactions t
    ON c.customer_id = t.customer_id;
💡
Pro Tip: In practice, analysts standardize on LEFT JOIN because it reads in the same direction as the FROM clause. RIGHT JOIN is rare and mostly appears to test whether you understand the symmetry.

4. Finding Unmatched Rows (Anti-Join)

To find rows in one table with no match in another, use a LEFT JOIN and filter WHERE the right table's key IS NULL. This is one of the most-asked join questions.

-- Customers who have NEVER made a transaction
SELECT c.customer_name
FROM customers c
LEFT JOIN transactions t
    ON c.customer_id = t.customer_id
WHERE t.txn_id IS NULL;

Returns customers 5 and 6 — they were kept by the LEFT JOIN but found no transaction match.

⚠️
Why check the right table's key? After a LEFT JOIN, unmatched right rows are entirely NULL, so the right key being NULL precisely marks a non-match.

5. Self Join and Cross Join

Self join — a table joined to itself

Used when rows relate to other rows in the same table — e.g., employees and their managers.

-- Each employee with their manager's name
SELECT e.emp_name AS employee, m.emp_name AS manager
FROM employees e
LEFT JOIN employees m
    ON e.manager_id = m.emp_id;

Using LEFT JOIN keeps the top boss (whose manager_id is NULL) in the result.

📝
Why aliases are required in a self join: Without aliases (e, m), the two copies of the table are indistinguishable, so column references become ambiguous.

Cross join — the Cartesian product

CROSS JOIN pairs every row of the first table with every row of the second.

-- 3 sizes × 4 colors = 12 combinations
SELECT s.size, c.color
FROM sizes s
CROSS JOIN colors c;

Useful for generating combinations. It also happens accidentally when you forget the ON condition.

6. The ON vs WHERE Trap (Critical)

For an outer join (LEFT/RIGHT), a filter on the right table behaves differently depending on whether you put it in ON or WHERE.

-- Filter in ON: still keeps ALL customers (shows txn only for one type)
SELECT c.customer_name, t.amount
FROM customers c
LEFT JOIN transactions t
    ON c.customer_id = t.customer_id
   AND t.amount > 1000;

Customers with no matching >1000 transaction still appear, with NULL amount.

-- Filter in WHERE: removes NULL rows → effectively an INNER JOIN
SELECT c.customer_name, t.amount
FROM customers c
LEFT JOIN transactions t
    ON c.customer_id = t.customer_id
WHERE t.amount > 1000;

Now customers with no >1000 transaction vanish — the WHERE kills the NULL rows the LEFT JOIN created.

⚠️
This exact question separates memorizers from understanders. A condition in ON preserves unmatched left rows; the same condition in WHERE turns a LEFT JOIN into an INNER JOIN. Always ask yourself where the filter should live.

7. Multi-Table Joins and JOIN vs UNION

Joining more than two tables

Chain joins one after another, each with its own ON. The result of the first join feeds the next.

SELECT e.emp_name, d.dept_name, l.city
FROM employees e
JOIN departments d ON e.dept_id = d.id
JOIN locations  l ON d.location_id = l.id;

JOIN vs UNION

JOINUNION
Directionhorizontal (adds columns)vertical (adds rows)
Purposecombine related tables side by sidestack results of two queries
Requirementa related keysame number/type of columns
📝
Memory hook: JOIN is side by side (more columns per row); UNION is on top of each other (more rows). They solve different problems.
📋 Stable content — Reviewed: August 2026

8. Interview Questions (with Model Answers)

Joins are the most-tested SQL topic. These are the questions interviewers reuse constantly. Self-test before revealing each answer.

IQ1. What is the difference between INNER JOIN and OUTER JOIN?

Model answer: "INNER JOIN returns only rows with a match in both tables. OUTER JOIN — LEFT, RIGHT, or FULL — keeps unmatched rows from one or both tables and fills the missing side with NULL. I'd use an outer join when 'no match' is a result I care about."

IQ2. What's the real difference between LEFT JOIN and RIGHT JOIN?

Model answer: "LEFT JOIN keeps all rows from the left (first) table; RIGHT JOIN keeps all from the right (second). They're mirror images — any RIGHT JOIN can be rewritten as a LEFT JOIN by swapping the table order. Most analysts standardize on LEFT JOIN."

IQ3. How do you find rows in one table with no match in another?

Model answer: "I use a LEFT JOIN and filter for the right table's key being NULL — LEFT JOIN ... WHERE right.key IS NULL. This keeps all left rows but only shows those that found no match." This is one of the most-asked join questions.

IQ4. What is a self join, and why do you need aliases?

Model answer: "A self join joins a table to itself — like employees to their managers. I need aliases because otherwise the two copies of the table are indistinguishable and column references become ambiguous."

IQ5. What is a CROSS JOIN?

Model answer: "It returns the Cartesian product — every row of one table paired with every row of the other. If one table has 4 rows and the other 3, you get 12 rows. It's useful for combinations, but it also happens accidentally when you forget the ON condition."

IQ6. Does a filter in ON behave the same as in WHERE?

Model answer: "For a LEFT JOIN, no. A condition on the right table in ON still keeps unmatched left rows as NULLs, but the same condition in WHERE removes those NULL rows and effectively turns the LEFT JOIN into an INNER JOIN. This is the classic trap."

IQ7. Can you join more than two tables? How?

Model answer: "Yes — I chain joins one after another, each with its own ON condition. The result of the first join becomes the input to the next. For inner joins the order doesn't change the final result, but for outer joins it can affect which rows are preserved."

IQ8. What's the difference between JOIN and UNION?

Model answer: "JOIN combines columns from two tables side by side (horizontal — more columns per row). UNION stacks rows of two queries on top of each other (vertical — more rows), and requires the same columns. They solve completely different problems."

IQ9. How do NULLs behave in a join condition?

Model answer: "A condition like a.id = b.id never matches when either side is NULL, because NULL = NULL is unknown, not true. So NULL keys never join and always end up as unmatched rows."

💡
How to answer join questions: Always say which table is "kept in full" and what happens to unmatched rows. One sentence — "LEFT JOIN keeps all left rows; unmatched right columns become NULL" — answers most join questions before they're even asked.

Hands-On Project: Join the Customers and Transactions

Using customers, transactions, and employees, write a query for each task.

Steps

  1. List customer names with their transaction amounts (only customers who have transactions).
  2. List ALL customers with their transaction amounts (NULL where none).
  3. List customers who have never made a transaction.
  4. List total transaction amount per customer (using a join + GROUP BY).
  5. List each employee with their manager's name.
View Solution / Walkthrough
-- 1. INNER JOIN (customers with transactions)
SELECT c.customer_name, t.amount
FROM customers c
INNER JOIN transactions t ON c.customer_id = t.customer_id;

-- 2. LEFT JOIN (all customers)
SELECT c.customer_name, t.amount
FROM customers c
LEFT JOIN transactions t ON c.customer_id = t.customer_id;

-- 3. Anti-join (customers with no transactions)
SELECT c.customer_name
FROM customers c
LEFT JOIN transactions t ON c.customer_id = t.customer_id
WHERE t.txn_id IS NULL;
-- → Vikram Singh, Ananya Das

-- 4. Total transaction amount per customer
SELECT c.customer_name, COALESCE(SUM(t.amount), 0) AS total_spent
FROM customers c
LEFT JOIN transactions t ON c.customer_id = t.customer_id
GROUP BY c.customer_name
ORDER BY total_spent DESC;

-- 5. Self join (employees + managers)
SELECT e.emp_name AS employee, m.emp_name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.emp_id;

Key Takeaways

1

INNER JOIN keeps only matches; LEFT JOIN keeps all left rows and NULLs the rest.

2

The anti-join LEFT JOIN ... WHERE key IS NULL finds rows with no match.

3

In outer joins, a filter in ON vs WHERE changes the result — the classic trap.

4

Self joins need aliases; cross joins multiply every row with every row.

5

JOIN is horizontal (columns), UNION is vertical (rows). NULL keys never join.

Objective Questions — Test Your Understanding

Q1. Which join returns only rows with a match in both tables?

Q2. Which join keeps ALL rows from the left table, filling unmatched right columns with NULL?

Q3. How do you find customers who have made NO transactions?

Q4. In a LEFT JOIN, what value fills the right-table columns for unmatched rows?

Q5. Which join joins a table to itself (e.g., employees to their managers)?