Working with Joins

1. Using INNER JOIN

SELECT o.id, c.full_name, o.total_cents
  FROM orders o
  JOIN customers c ON c.id = o.customer_id;
ResultDetail
RowsMatching pairs only
SynonymJOIN = INNER JOIN

2. Using LEFT JOIN

SELECT c.id, c.full_name, count(o.id) AS order_count
  FROM customers c
  LEFT JOIN orders o ON o.customer_id = c.id
 GROUP BY c.id;
BehaviorDetail
PreservesAll rows from left side
Unmatched rightNULL columns

3. Using RIGHT JOIN

SELECT o.id, c.full_name
  FROM customers c RIGHT JOIN orders o ON o.customer_id = c.id;
Note: Equivalent to swapping operand order with LEFT JOIN; LEFT is more idiomatic.

4. Using FULL OUTER JOIN

SELECT a.id, b.id
  FROM table_a a FULL OUTER JOIN table_b b ON a.key = b.key;
ReturnsDetail
All rowsFrom both sides
UnmatchedNULL for missing side

5. Using CROSS JOIN

SELECT s.name, c.code FROM sizes s CROSS JOIN colors c;
-- Equivalent: SELECT ... FROM sizes s, colors c;

6. Using Self Join

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

7. Using NATURAL JOIN

SELECT * FROM orders NATURAL JOIN customers;
Warning: NATURAL JOIN auto-matches any columns with the same name. Avoid—silently breaks when schemas evolve.

8. Using JOIN with ON Clause

SELECT * FROM a JOIN b ON a.x = b.y AND a.tenant = b.tenant;
PredicateGoes In
Join conditionON clause
Row filterWHERE (post-join)
Filter on right side of LEFT JOINON to preserve outer rows

9. Using JOIN with USING Clause

SELECT * FROM orders JOIN customers USING (customer_id);
Note: Both columns must be named identically; result has only one merged column.

10. Chaining Multiple Joins

SELECT o.id, c.full_name, p.name, oi.qty
  FROM orders o
  JOIN customers c   ON c.id = o.customer_id
  JOIN order_items oi ON oi.order_id = o.id
  JOIN products p     ON p.id = oi.product_id;

11. Understanding Join Order and Performance

MethodBest For
Nested LoopSmall outer + indexed inner
Hash JoinLarge unsorted inputs, equi-join
Merge JoinSorted inputs (large equi-join)
Note: Planner re-orders joins; force order with join_collapse_limit = 1 or CTE materialization.

12. Using JOIN with WHERE Clause

SELECT * FROM orders o
  JOIN customers c ON c.id = o.customer_id
 WHERE c.country = 'US' AND o.placed_at >= '2026-01-01';