JOIN в SQL соединяет строки двух таблиц по общему полю, например заказы и клиентов по номеру клиента. Основных видов четыре: INNER JOIN оставляет только совпадающие строки, LEFT JOIN — все строки левой таблицы, RIGHT JOIN — все строки правой, FULL JOIN — все строки обеих. Там, где пары не нашлось, в столбцах подставляется NULL.
Главное за 30 секунд
Возьмём две таблицы: клиентов и их заказы. У клиента Ольги заказов нет, а заказ 104 оформлен на клиента с номером 4, которого нет в таблице клиентов.
| clients | |
|---|---|
| id | name |
| 1 | Анна |
| 2 | Борис |
| 3 | Ольга |
| orders | ||
|---|---|---|
| id | client_id | amount |
| 101 | 1 | 5 000 |
| 102 | 1 | 2 500 |
| 103 | 2 | 7 000 |
| 104 | 4 | 1 200 |
Таблицы соединяются по условию clients.id = orders.client_id. От вида JOIN зависит, что произойдёт со строками без пары: с Ольгой и с заказом 104.
SELECT c.name, o.id AS order_id, o.amount
FROM clients c
INNER JOIN orders o ON c.id = o.client_id; Результат — три строки: два заказа Анны и заказ Бориса. Ольга без заказов и заказ 104 без клиента в результат не попали. Слово INNER можно не писать: просто JOIN означает то же самое.
| name | order_id | amount |
|---|---|---|
| Анна | 101 | 5 000 |
| Анна | 102 | 2 500 |
| Борис | 103 | 7 000 |
SELECT c.name, o.id AS order_id, o.amount
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id; Результат — четыре строки: к трём совпадениям добавилась Ольга, у которой в столбцах заказа стоит NULL. LEFT JOIN используют, когда важно не потерять ни одной строки основной таблицы, например всех клиентов при подсчёте их заказов.
| name | order_id | amount |
|---|---|---|
| Анна | 101 | 5 000 |
| Анна | 102 | 2 500 |
| Борис | 103 | 7 000 |
| Ольга | NULL | NULL |
SELECT c.name, o.id AS order_id, o.amount
FROM clients c
RIGHT JOIN orders o ON c.id = o.client_id; Результат — четыре строки: три совпадения и заказ 104, у которого имя клиента NULL. RIGHT JOIN встречается редко: тот же результат получают через LEFT JOIN, поменяв таблицы местами.
SELECT c.name, o.id AS order_id, o.amount
FROM clients c
FULL JOIN orders o ON c.id = o.client_id; Результат — пять строк: три совпадения, Ольга без заказов и заказ 104 без клиента. FULL JOIN помогает сверять два справочника и находить расхождения. В MySQL его нет — там объединяют результаты LEFT и RIGHT JOIN через UNION.
| Вид | Что попадает в результат | Строк в примере |
|---|---|---|
| INNER JOIN | Только строки, у которых есть пара в обеих таблицах | 3 |
| LEFT JOIN | Все строки левой таблицы + пары из правой или NULL | 4 |
| RIGHT JOIN | Все строки правой таблицы + пары из левой или NULL | 4 |
| FULL JOIN | Все строки обеих таблиц | 5 |
| CROSS JOIN | Каждая строка левой с каждой строкой правой, без условия | 3 × 4 = 12 |
Отдельно выделяют SELF JOIN — соединение таблицы с самой собой, например чтобы вывести сотрудника рядом с его руководителем из той же таблицы.
Соединяйте таблицы на реальных бизнес-кейсах
Курс «Обработка и анализ данных в SQL» от SF Education: 6 практических заданий и 2 бизнес-кейса за 1 месяц, JOIN, группировки и аналитические запросы.
WHERE o.amount > 1000 отбросит строки, где amount равен NULL, и LEFT JOIN фактически превратится в INNER. Условие для правой таблицы переносят в ON.Чтобы найти клиентов без заказов, используют LEFT JOIN и проверку на NULL в правой таблице:
SELECT c.id, c.name
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
WHERE o.id IS NULL; В нашем примере запрос вернёт Ольгу. Так же ищут товары без продаж или платежи, которые не привязались к счёту.
Запрос считает число заказов и сумму покупок по каждому клиенту, включая клиентов без заказов:
SELECT c.name,
COUNT(o.id) AS orders,
COALESCE(SUM(o.amount), 0) AS total
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
GROUP BY c.name
ORDER BY total DESC; COUNT(o.id) не считает NULL, поэтому у Ольги будет 0 заказов, а COALESCE заменит пустую сумму на ноль. Основы запросов — в статье что такое SQL.
INNER JOIN возвращает только строки, у которых есть пара в обеих таблицах. LEFT JOIN возвращает все строки левой таблицы, а там, где пары в правой таблице нет, подставляет NULL. Поэтому LEFT JOIN никогда не возвращает меньше строк, чем в левой таблице.
Да. Если написать просто JOIN без уточнения, база выполнит INNER JOIN. Слово INNER добавляют для читаемости, чтобы сразу было видно вид соединения.
Так происходит при связи «один ко многим»: если у клиента три заказа, его строка повторится три раза. Это нормальное поведение JOIN. Если нужна одна строка на клиента, сначала сгруппируйте заказы в подзапросе, а потом соединяйте.
Используйте LEFT JOIN и условие WHERE правая_таблица.id IS NULL. Запрос вернёт строки левой таблицы, для которых не нашлось пары, например клиентов без заказов. Тот же результат даёт конструкция NOT EXISTS.
Нет, MySQL не поддерживает FULL JOIN. Его заменяют объединением двух запросов через UNION: первый с LEFT JOIN, второй с RIGHT JOIN. В PostgreSQL, Microsoft SQL Server и Oracle FULL JOIN есть.
Сколько угодно: каждый следующий JOIN присоединяет таблицу к уже полученному результату. На практике аналитики соединяют три-пять таблиц, а для больших запросов используют CTE через WITH, чтобы запрос оставался читаемым.
Закрепите JOIN на практике
На курсе «Обработка и анализ данных в SQL» вы решите задачи на соединение таблиц, агрегаты и подзапросы на данных, похожих на рабочие.