JOIN в SQL: INNER, LEFT, RIGHT, FULL, CROSS

Все виды соединений таблиц с наглядными примерами, отличие WHERE от ON, самосоединение и типовые ошибки с дублированием строк.

JOIN соединяет строки двух таблиц по условию. Разница между видами — только в том, что делать со строками, для которых пары не нашлось.

-- Студенты            Оценки
-- id  fio             student_id  predmet  ball
-- 1   Иванов          1           Матан    5
-- 2   Петров          1           Физика   4
-- 3   Сидоров         2           Матан    3

INNER JOIN — только совпадения

SELECT s.fio, o.predmet, o.ball
FROM Студенты s
INNER JOIN Оценки o ON o.student_id = s.id;
-- Иванов/Матан/5, Иванов/Физика/4, Петров/Матан/3
-- Сидоров не попал: у него нет оценок

LEFT JOIN — все строки слева

SELECT s.fio, o.predmet, o.ball
FROM Студенты s
LEFT JOIN Оценки o ON o.student_id = s.id;
-- добавится строка: Сидоров / NULL / NULL

Это самый частый рабочий инструмент: «покажи всех студентов, в том числе тех, у кого ничего нет». В связке с IS NULL находит «сирот».

-- студенты вообще без оценок
SELECT s.fio
FROM Студенты s
LEFT JOIN Оценки o ON o.student_id = s.id
WHERE o.student_id IS NULL;

RIGHT и FULL

ON или WHERE — в чём разница

Для INNER JOIN разницы нет. Для LEFT JOIN — принципиальная: условие в ON применяется до соединения и сохраняет строки без пары, а условие в WHERE отсекает их после и превращает LEFT в INNER.

-- Все студенты, а по Матану — оценка, если есть
SELECT s.fio, o.ball
FROM Студенты s
LEFT JOIN Оценки o ON o.student_id = s.id AND o.predmet = 'Матан';

-- А так Сидоров исчезнет — типичная ошибка
SELECT s.fio, o.ball
FROM Студенты s
LEFT JOIN Оценки o ON o.student_id = s.id
WHERE o.predmet = 'Матан';
Если после JOIN строк стало больше, чем в исходной таблице, — вы соединяете по неуникальному полю. Это не ошибка сама по себе, но при подсчёте SUM даст завышенные суммы.

Самосоединение

-- сотрудник и его руководитель из одной таблицы
SELECT e.fio AS сотрудник, b.fio AS руководитель
FROM Сотрудники e
LEFT JOIN Сотрудники b ON e.boss_id = b.id;

Соединение нескольких таблиц

SELECT g.название AS группа, p.название AS предмет, ROUND(AVG(o.ball), 2) AS средний
FROM Оценки o
JOIN Студенты s ON s.id = o.student_id
JOIN Группы   g ON g.id = s.группа_id
JOIN Предметы p ON p.id = o.предмет_id
GROUP BY g.название, p.название
HAVING AVG(o.ball) < 4
ORDER BY средний;

Запомните порядок выполнения: FROM и JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. Поэтому в WHERE нельзя ссылаться на псевдоним из SELECT, а в HAVING — можно фильтровать по агрегатам.

Частые вопросы

Чем JOIN лучше подзапроса?

Обычно читаемостью и планом выполнения: оптимизатор чаще эффективнее обрабатывает соединение. Но коррелированный подзапрос с EXISTS иногда быстрее, если нужна лишь проверка наличия.

Почему после JOIN появились дубликаты?

Потому что в правой таблице несколько строк соответствуют одной левой. Либо это нормально и нужна группировка, либо вы забыли условие в ON.

Читайте также

Сделаем работу по этой теме

Опишите задачу — ответим в течение 15 минут в личных сообщениях ВКонтакте, назовём срок и цену. Предоплаты за оценку нет.

  • Оценка заявки бесплатно
  • Правки по замечаниям преподавателя
  • Работы по всем техническим и IT-дисциплинам

Нажимая кнопку, вы соглашаетесь на обработку указанных данных для ответа на заявку.