Self joins, CROSS JOIN & FULL OUTER emulation
Join a table to itself, build combinations with CROSS JOIN, emulate FULL OUTER JOIN and use USING.
You already know INNER, LEFT and RIGHT joins. This lesson covers the rest of the toolbox: self joins for hierarchies and comparisons within one table, CROSS JOIN for combinations, emulating FULL OUTER JOIN, non-equality joins, and the USING shorthand.
Self joins#
A self join joins a table to itself using two different aliases. The classic case is an employee table where manager_id points at another employee:
Show each person with their manager's name:
Think of e and m as two copies of the same list. For each employee row e, we look up the row m whose id is the employee's manager_id. A LEFT JOIN keeps Asha, who has no manager.
Self joins also compare rows with each other. Who earns more than their own manager?
How many direct reports does each manager have?
A self join goes one level at a time. To walk a whole tree of any depth (everyone under the CEO, however deep), you'll use a recursive CTE in the CTEs lesson.
Finding pairs#
Self joins with < produce each pair once, which is handy for spotting duplicates or matching things up:
Using a.id < b.id (rather than <>) avoids both pairing a row with itself and listing (Meera, Karan) as well as (Karan, Meera).
CROSS JOIN: every combination#
A CROSS JOIN pairs every row of one table with every row of another. This is the Cartesian product:
3 sizes × 2 colours = 6 rows. Cross joins are useful for generating combinations (product variants, a calendar × store grid for reports), but row counts multiply fast: two 10,000-row tables give 100 million rows. An accidental cross join, usually from a missing ON clause, is a common cause of queries that never finish.
The old comma syntax
FROM a, b WHERE a.id = b.a_idis an inner join written with the condition inWHERE. If you forget theWHERE, it becomes a cross join. Prefer explicitJOIN ... ON.
FULL OUTER JOIN (emulated)#
A full outer join returns all rows from both sides, matched where possible. MySQL doesn't support FULL OUTER JOIN, but you can build one with UNION:
UNION removes the duplicate copy of Alan, who matched in both halves. On large tables, a faster version uses UNION ALL and keeps only the unmatched rows in the second half (... RIGHT JOIN ... WHERE c.email IS NULL), which avoids the duplicate-removal step.
Non-equality joins#
ON can hold any condition, not just =. A range join matches values against bands:
USING and NATURAL JOIN#
When the join columns have the same name in both tables, USING is a shorthand:
With USING, the shared column appears once and you can refer to it unqualified (id). NATURAL JOIN goes one step further and joins on every column with the same name, automatically. Avoid it: adding an innocent column such as created_at to both tables silently changes the join.
Semi-joins: "has at least one match"#
Sometimes you only want to know whether a match exists, without repeating rows for every match. Joining would duplicate managers once per report. Instead use EXISTS (or IN), which you'll study in the next lesson:
Summary of join types#
What's next#
That EXISTS was a sneak preview. Next: subqueries, which are queries inside queries, including correlated subqueries.
Check your understanding
Quick quiz
1.In a self join
employees e JOIN employees m ON e.manager_id = m.id, what doesmrepresent?2.Table A has 4 rows and table B has 3 rows. How many rows does
A CROSS JOIN Breturn?3.MySQL has no FULL OUTER JOIN. How do you emulate it?
Finished reading?
Mark this lesson complete to track your progress.