INNER JOIN
Return only the rows that match in both tables — and know when a non-unique key silently duplicates them.
Syntax
SELECT ...
FROM left_table lt
INNER JOIN right_table rt
ON lt.key = rt.key;INNER JOIN and plain JOIN are the same thing — the INNER is optional.
What it does
Keeps only the rows with matching keys in both tables. It's the default join when you're filtering to relationships that actually exist.
Example
Loading editor…
Customers 6 and 7 (Wayne Enterprises, Soylent) have no orders — they simply
don't appear. That's INNER JOIN's defining behavior; if you need them anyway,
that's a LEFT JOIN.
Fan-out: the row count can grow
If the right table has more than one matching row per key, the left row repeats — once per match:
Loading editor…
Customer 1 has 3 orders, so joining customers to orders on customer_id
turns that one customer row into three. This is correct when you want
one row per order — but if you then SUM() a customer-level column without
grouping, you'll silently multiply it. Always check the row count against what
you expect before trusting a join's aggregate.
Hit this as an actual error?
- LEFT JOIN — keep unmatched left rows instead of dropping them.
- Rows missing in another table — the opposite question: what INNER JOIN drops.
- GROUP BY — the fix for fan-out when aggregating.
Safety check before shipping
- confirm the join key represents the intended relationship
- inspect row counts before and after the join
- decide whether duplicates (fan-out) are valid or indicate a broken relationship