Lesson 6 of 10 · 10 min · 2 hands-on steps

Combining Tables with JOIN

See exactly how INNER and LEFT JOIN match rows, then write your own.

Why data lives in separate tables

Instead of copying a customer's name onto every order, orders stores a customer_id that points to a row in customers. That pointer is called a foreign key. A JOIN follows it.

See it happen

Switch between INNER and LEFT JOIN and watch which rows survive:

🔗 How JOIN combines tables
SELECT c.name, o.item
FROM customers c
INNER JOIN orders o ON o.customer_id = c.id;
customers
idname
1Amara
2Bo
3Carla
4Dev
orders
idcustomer_iditem
101Keyboard
111Mouse
123Monitor
139Cable
result
nameitem
AmaraKeyboard
AmaraMouse
CarlaMonitor

INNER JOIN keeps only rows that match on both sides. Dev has no orders, and order 13 has no customer, so both disappear.

Green rows found a match. Faded rows didn't. In a LEFT JOIN, unmatched customers stay with NULLs.

Writing joins

SQL · try it
SELECT c.name, o.ordered_on, o.quantity
FROM orders o
JOIN customers c ON c.id = o.customer_id;
  • orders o gives the table a short nickname (an alias)
  • ON says how the rows match

LEFT JOIN to find what's missing

SQL · try it
SELECT c.name, COUNT(o.id) AS orders
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.id
ORDER BY orders DESC;

"Customers with no orders" and "products never sold" are classic interview and real-world questions. The answer is almost always a LEFT JOIN plus IS NULL.

🧪 Practice: 2 steps

0 / 2 done

Step 1 of 2 · Who ordered what

Return each order's customer name and product name (columns customer and product), ordered by order id.

Tables: orders(id, customer_id, product_id, …), customers(id, name, …), products(id, name, price).

SQL
SELECT o.id, o.customer_id, o.product_id FROM orders o;

Output appears here. Press Run or Ctrl/⌘ + Enter.

✅ Check your understanding

  1. Which JOIN keeps every row from the left table, even without a match?

Create a free account to track your progress.