JOIN — одна из самых важных конструкций в SQL. И одна из самых частых тем на собеседованиях. В этой статье разберём все виды JOIN на одном примере, чтобы разница была наглядной.
Пример: таблицы заказов
Допустим, у нас есть две таблицы:
users — список пользователей:
| id | name |
|---|---|
| 1 | Алиса |
| 2 | Борис |
| 3 | Виктор |
orders — заказы:
| id | user_id | amount |
|---|---|---|
| 1 | 1 | 500 |
| 2 | 1 | 300 |
| 3 | 2 | 800 |
| 4 | 99 | 100 |
Заказ с user_id=99 — «сирота», такого пользователя нет. Виктор (id=3) заказов не делал.
INNER JOIN — только совпадения
Возвращает строки, которые есть в обеих таблицах.
SELECT u.name, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
Результат:
| name | amount |
|---|---|
| Алиса | 500 |
| Алиса | 300 |
| Борис | 800 |
Виктор не попал — у него нет заказов. Заказ 99 не попал — нет пользователя.
LEFT JOIN — все из левой таблицы
Возвращает все строки из левой таблицы, а из правой — только совпадения. Нет совпадения — NULL.
SELECT u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
Результат:
| name | amount |
|---|---|
| Алиса | 500 |
| Алиса | 300 |
| Борис | 800 |
| Виктор | NULL |
Виктор теперь есть, но amount = NULL. Это самый частый JOIN в аналитике.
Лайфхак: найти пользователей БЕЗ заказов
SELECT u.name
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
Результат: только Виктор.
RIGHT JOIN — все из правой таблицы
Зеркальный LEFT JOIN. На практике используется редко — проще поменять таблицы местами. RIGHT JOIN существует в стандарте SQL для симметрии, но в реальных проектах вы вряд ли будете его использовать. Если кажется, что нужен RIGHT JOIN, просто поменяйте таблицы местами и используйте LEFT JOIN — так будет понятнее коллегам.
SELECT u.name, o.amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
Результат:
| name | amount |
|---|---|
| Алиса | 500 |
| Алиса | 300 |
| Борис | 800 |
| NULL | 100 |
Заказ user_id=99 попал, но name = NULL.
FULL JOIN — всё из обеих таблиц
Объединяет LEFT и RIGHT — строки из обеих таблиц, NULL там, где нет совпадения.
SELECT u.name, o.amount
FROM users u
FULL JOIN orders o ON u.id = o.user_id;
Результат:
| name | amount |
|---|---|
| Алиса | 500 |
| Алиса | 300 |
| Борис | 800 |
| Виктор | NULL |
| NULL | 100 |
Важно: MySQL не поддерживает FULL JOIN. Там эмулируют через
UNIONиз LEFT и RIGHT JOIN.
CROSS JOIN — декартово произведение
Каждая строка левой таблицы соединяется с каждой строкой правой. 3 пользователя × 4 заказа = 12 строк.
SELECT u.name, o.amount
FROM users u
CROSS JOIN orders o;
Применяется редко — например, для генерации комбинаций или тестовых данных.
Как запомнить раз и навсегда
| JOIN тип | Что возвращает |
|---|---|
| INNER | Только совпадения |
| LEFT | Все из левой + совпадения из правой |
| RIGHT | Все из правой + совпадения из левой |
| FULL | Всё из обеих таблиц |
| CROSS | Все комбинации (без условия ON) |
На собеседованиях чаще всего спрашивают разницу между INNER и LEFT. Знай ответ наизусть: LEFT сохраняет все строки из первой таблицы, INNER — только совпадающие.
Бонус: SELF JOIN
Иногда нужно соединить таблицу с самой собой — например, найти сотрудников и их руководителей в одной таблице employees:
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
Здесь одна таблица используется дважды с разными алиасами. LEFT JOIN нужен, чтобы CEO (у которого нет руководителя) тоже попал в результат.
Про производительность
Все JOIN (кроме CROSS) требуют сопоставления строк. Чтобы это происходило быстро, на столбцах соединения (u.id и o.user_id в наших примерах) должны быть индексы. Без них база будет делать полное сканирование таблиц — на больших данных это катастрофически медленно.
Не используйте устаревший синтаксис через запятую:
-- ❌ legacy-стиль, легко сломать SELECT * FROM users u, orders o WHERE u.id = o.user_id;Если забыть условие
WHERE— получите CROSS JOIN и миллионы строк. Всегда пишите явныйJOIN.
Практика
Попробуй написать запросы с JOIN на реальных данных прямо в браузере — в нашем тренажёре. Никакой установки, сразу в дело.