SQL JOIN объединяет строки из двух или более таблиц на основе связанных колонок. Без понимания типов соединений невозможно корректно строить запросы к реляционным базам данных.
Что такое JOIN
JOIN — это операция, которая комбинирует строки из разных таблиц по условию (обычно равенству ключей). Вместо хранения всех данных в одной громоздкой таблице реляционная модель распределяет их по нескольким связанным сущностям, а JOIN позволяет собирать нужную картину обратно.
Существует пять основных видов соединений:
- INNER JOIN — пересечение: только совпадающие строки
- LEFT JOIN (LEFT OUTER) — все строки левой таблицы плюс совпадения из правой
- RIGHT JOIN (RIGHT OUTER) — все строки правой таблицы плюс совпадения из левой
- FULL JOIN (FULL OUTER) — объединение: все строки обеих таблиц
- CROSS JOIN — декартово произведение: каждая строка с каждой
Формула и основные правила
Общий синтаксис:
SELECT столбцы
FROM таблица_A
[INNER | LEFT | RIGHT | FULL] JOIN таблица_B
ON таблица_A.ключ = таблица_B.ключ;
Ключевые правила:
- Условие после
ONопределяет, как сопоставлять строки. - Если совпадений нет, в OUTER JOIN отсутствующие значения заменяются на
NULL. INNER JOINотбрасывает строки без совпадений с обеих сторон.CROSS JOINне требуетON— он соединяет всё со всем, даваяN × Mстрок.- Можно соединять более двух таблиц последовательно:
A JOIN B JOIN C.
Пример
Возьмём две таблицы.
employees
| id | name | dept_id |
|---|---|---|
| 1 | Анна | 10 |
| 2 | Борис | 20 |
| 3 | Вера | 30 |
| 4 | Глеб | NULL |
departments
| dept_id | dept_name |
|---|---|
| 10 | Финансы |
| 20 | Маркетинг |
| 40 | Логистика |
INNER JOIN
SELECT e.name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
Результат — только сотрудники с существующим отделом:
| name | dept_name |
|---|---|
| Анна | Финансы |
| Борис | Маркетинг |
Вера (отдел 30 не существует) и Глеб (NULL), а также отдел Логистика — отброшены.
LEFT JOIN
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;
Все сотрудники сохраняются:
| name | dept_name |
|---|---|
| Анна | Финансы |
| Борис | Маркетинг |
| Вера | NULL |
| Глеб | NULL |
RIGHT JOIN
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id;
Все отделы сохраняются:
| name | dept_name |
|---|---|
| Анна | Финансы |
| Борис | Маркетинг |
| NULL | Логистика |
FULL JOIN
SELECT e.name, d.dept_name
FROM employees e
FULL JOIN departments d ON e.dept_id = d.dept_id;
Сохраняется всё:
| name | dept_name |
|---|---|
| Анна | Финансы |
| Борис | Маркетинг |
| Вера | NULL |
| Глеб | NULL |
| NULL | Логистика |
CROSS JOIN
SELECT e.name, d.dept_name
FROM employees e
CROSS JOIN departments d;
Получим 4 × 3 = 12 строк — каждый сотрудник в паре с каждым отделом. Применяется редко: для генерации комбинаций, расписаний, тестовых данных.
SELF JOIN
Отдельная техника — соединение таблицы с самой собой. Полезно для иерархий (сотрудник — руководитель):
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
Типичные ошибки
Путаница INNER и LEFT. Если хочется получить «всех клиентов и их заказы, даже если заказов нет», нужен LEFT JOIN. INNER JOIN молча выкинет клиентов без заказов, и отчёт будет неполным.
Фильтрация в WHERE вместо ON для OUTER JOIN. Условие
WHERE d.dept_name = 'Финансы'после LEFT JOIN превращает его в фактический INNER JOIN, потому что NULL-строки не пройдут фильтр. Если нужно отфильтровать правую таблицу до соединения — переносите условие вON.Дубликаты после JOIN. Если ключ соединения не уникален в одной из таблиц, количество строк умножается. Например, у одного сотрудника несколько проектов — JOIN с проектами «размножит» строки. Решение: агрегация (
GROUP BY,DISTINCT) или предварительное сужение через подзапрос.Забытое условие ON. В некоторых СУБД пропуск
ONили некорректное условие даёт CROSS JOIN или ошибку. На больших таблицах это означает миллионы лишних строк и зависший запрос.
Когда стоит обратиться за помощью
JOIN — фундамент SQL, но в реальных задачах возникают более сложные сценарии: соединение пяти-шести таблиц, оптимизация по индексам, антисоединения через NOT EXISTS, оконные функции поверх JOIN. Если запрос работает медленно или возвращает не те данные, и план выполнения не помогает разобраться — наш сервис Solvr поможет разобрать конкретный запрос, объяснить логику ошибки и предложить корректный вариант с пояснением каждого шага. Это удобно, когда нужно не просто получить ответ, а понять, почему именно так.