OUTER JOIN
Outer join сохраняет строки одной или обеих сторон, даже если соответствие не найдено. Недостающие столбцы заполняются NULL.
LEFT JOIN
SELECT c.id, c.name, p.id AS purchase_id
FROM customer c
LEFT JOIN purchase p
ON p.customer_id = c.id
ORDER BY c.id, p.id;Все покупатели останутся. Покупатель без покупок получит одну строку с purchase_id = NULL.
Полезный запрос «у кого нет покупок»:
SELECT c.id, c.name
FROM customer c
LEFT JOIN purchase p ON p.customer_id = c.id
WHERE p.id IS NULL;Если в правой таблице подходящих строк несколько, левая строка всё равно повторяется.
Условие в ON и WHERE
Это главное различие, которое нужно помнить:
-- сохраняет всех покупателей;
-- справа присоединяются только оплаченные покупки
FROM customer c
LEFT JOIN purchase p
ON p.customer_id = c.id
AND p.status = 'PAID'-- удаляет строки без покупки и фактически делает результат похожим на INNER JOIN
FROM customer c
LEFT JOIN purchase p ON p.customer_id = c.id
WHERE p.status = 'PAID'В первом варианте фильтр участвует в поиске соответствия. Во втором он применяется после join, а выражение NULL = 'PAID' не истинно.
RIGHT JOIN
RIGHT JOIN сохраняет все строки правой стороны. Его всегда можно переписать как LEFT JOIN, поменяв таблицы местами. В длинном запросе единое направление LEFT JOIN часто проще читать.
FULL OUTER JOIN
FULL OUTER JOIN сохраняет:
- совпавшие пары;
- строки только из левой таблицы;
- строки только из правой таблицы.
SELECT a.external_key, b.external_key
FROM import_a a
FULL OUTER JOIN import_b b
ON b.external_key = a.external_key;Так удобно сверять два набора. Поддержка FULL OUTER JOIN зависит от СУБД. Переносимая эмуляция требует аккуратно объединить left-only, совпавшие и right-only строки через UNION ALL.
Трёхзначная логика
Условие SQL получает TRUE, FALSE или UNKNOWN. В ON парой считаются только строки с TRUE; в WHERE остаются только строки с TRUE. Поэтому NULL требует IS NULL, а не = NULL.
На собеседовании
Как WHERE может сломать left join? Фильтр по nullable-столбцу правой стороны отбрасывает строки, созданные без соответствия.
Что возвращает full join? Все совпадения и несовпавшие строки обеих сторон.
Связанные заметки: INNER JOIN, Многотабличные запросы операция JOIN, SQL.