JOINs: Combining Tables on a Key

SQL & Querying
27 / 47

A JOIN stitches rows from two tables together wherever a condition - usually a foreign key matching a primary key - is true, turning ids back into names.

The Analogy (Read This First)

A coat-check ticket. The coat rack stores ticket numbers, not owners; the ticket book maps numbers to people. A JOIN lines the two lists up by ticket number so you can see who owns which coat.

Deep Dive Analysis

Well-designed schemas store each fact once, so an order holds a customer_id, not a name. To see names you JOIN. INNER JOIN returns one row for every pair of rows where the ON condition is true; a row with no partner on the other side is dropped.

SELECT o.id, c.name, o.amount
FROM orders AS o
INNER JOIN customers AS c ON c.id = o.customer_id
WHERE o.amount > 500;

Aliases (orders AS o) shorten table names and become required when the same column name exists in both tables: id alone is ambiguous, o.id versus c.id is not. Qualify every column with its alias as soon as more than one table is involved.

Filter and sort after joining as usual: the join builds the combined rows first, then WHERE and ORDER BY work on them. ON is for the matching rule; put your real filters in WHERE. For an INNER JOIN the two behave the same, but the habit matters once LEFT JOINs arrive.

Self-join. A table can join to itself when it references itself - an employee row has manager_id pointing at another employee. Give the table two aliases so each plays a different role:

SELECT e.name AS employee, m.name AS manager
FROM employees AS e
INNER JOIN employees AS m ON m.id = e.manager_id;

Chaining joins. Add one JOIN per extra table and read it as a path: each ON links the table you just added to one already in the query.

SELECT o.id, c.name, ct.country
FROM orders AS o
JOIN customers AS c ON c.id = o.customer_id
JOIN cities    AS ct ON ct.id = c.city_id;

Duplicates are a join symptom. If one customer has five orders, that customer appears five times in the joined result. When a count looks too big after a join, you are counting joined rows, not customers: use COUNT(DISTINCT c.id) or aggregate before you join.

A JOIN with a missing or wrong ON condition is effectively a cross join: every row paired with every row, so 1,000 x 1,000 rows becomes 1,000,000 results. If a query suddenly returns far too many rows, check the ON condition first.

Key Bullets
  • ON states how rows match (usually foreign key = primary key); INNER JOIN keeps only matched pairs.
  • Alias tables and qualify columns (o.id, c.id) whenever more than one table is in play.
  • A self-join needs two aliases of the same table - one per role.
  • Chain JOINs like a path; each ON connects the new table to one already present.
  • Duplicated rows after a join mean one-to-many: count DISTINCT or aggregate first.
  • A wrong or missing ON explodes the row count (cross join).
Real-World Examples
Show account names instead of account ids on a transactions listEmployee-to-manager lookups: join employees to itself on manager_idOrders -> customers -> cities: a three-table chain

Curated Curation & Deep Insights

ScaleDojo Certified
Video Tutorial Pending

Our system architects are vetting high-quality, authorized video guides for JOINs: Combining Tables on a Key with zero third-party platform links.

Verification in Progress
Reading Material Pending

We are preparing premium, zero-competitor deep-dives for JOINs: Combining Tables on a Key. Authorized reading references will appear automatically.

Verification in Progress