Interactive Lab · Data & SQL
You have Customers and Orders. Some customers never ordered anything; one order points at a customer who isn't in the table (an orphan). When you join them, the join typenot magic, decides whether those unmatched rows are kept (with NULLs) or silently dropped. Pick a join below and watch exactly which rows live and which vanish.
🎬 Watch the 45-second explainer, then try it yourself below ↓
▶ The playground, pick a join, watch the rows
| id | name |
|---|
| id | customer_id | item |
|---|
Result of the join
| c.id | c.name | o.id | o.customer_id | o.item |
|---|
The "missing data" bug, made visible
A report asks "list every customer and their total spend." A developer writes an INNER JOIN. It runs fine, no error. But the two customers who never ordered silently disappear from the report, and finance wonders why the customer count dropped. Nothing crashed; the wrong join type just threw rows away without telling anyone. That's why joins are a top source of quiet data bugs: the failure is invisible unless you know to look for it.
The SQL that's actually running
Joins are the daily verb of every data job: attaching orders to customers, events to users, payments to invoices. The orphan-rows intuition you just built (LEFT vs FULL OUTER) is how analysts audit data quality, and join choice is the first thing reviewed in any slow or wrong query, in interviews and in production.
Flip between INNER and LEFT, which customer appears/disappears, and why? Now try RIGHT: which single row shows a NULL customer (the orphan order)? Compare LEFT vs RIGHT, they're mirror images: LEFT keeps every customer, RIGHT keeps every order. Which join would you use to find bugs, i.e. surface customers with no orders and orders with no customer at once? And why does CROSS explode to so many rows?
The takeaway