Joins I — semantics
Concept  ·  SQL & Querying

A table joined to itself (employee -> manager) needs distinct aliases and a non-reflexive condition.

The aliases are the entire trick: s and m are the same rows wearing different roles, and every column reference must pick a costume — unaliased columns are ambiguity errors at best, silent wrong-role picks at worst. Three standard uses: hierarchy hops (one level per join — unknown depth graduates to recursive_cte), row-pairings (join on the common column, s.id < s2.id to avoid self- and mirror-pairs), and offset comparisons.

See it break
staff
idnamementor_id
1IoNULL
2Pax1
3Rae1
The trap
SELECT
  s.name,
  m.name AS mentor
FROM
  staff s
  JOIN staff m ON m.id = s.mentor_id
ORDER BY
  s.name;
The fix
SELECT
  s.name,
  m.name AS mentor
FROM
  staff s
  LEFT JOIN staff m ON m.id = s.mentor_id
ORDER BY
  s.name;
The trap
PaxIo
RaeIo
The fix
IoNULL
PaxIo
RaeIo

The INNER self-join dropped Io, the root contributor with no mentor — a table joined to itself needs LEFT to keep the roots, and the two aliases are the whole trick.

The rule

Meaningful aliases (emp/mgr, not a/b); LEFT when roots must survive; the < trick on pairings.

Shows up elsewhere
Recursive CTE basicsLAG detects the gap
Try one →Prove it in practice →