← К оглавлению занятия

Занятие 22. Операторы JOIN и UNION

📁 Блок: SQL / MySQL / Связи и JOIN ⏱️ Время изучения: ~90 мин 🎯 Сложность: Средняя
#select #from #join #union

⚡ Кратко: суть темы

JOIN соединяет таблицы по ключу, UNION складывает строки из разных запросов.

  • INNER JOIN — только совпадения; LEFT JOIN — всё слева + совпадения справа.
  • UNION удаляет дубликаты, UNION ALL — нет.
  • У UNION должно совпадать число столбцов и типы.

📖 Горизонтальное объединение: UNION и UNION ALL

Операторы UNION и UNION ALL объединяют результаты двух и более SELECT-запросов в один результирующий набор. Строки первого запроса идут первыми, затем строки второго — и так далее.

UNION

  • Удаляет полные дубликаты строк.
  • Требует больше памяти и времени, чем UNION ALL, потому что сравнивает строки между наборами.
SELECT column1, column2 FROM table1
UNION
SELECT column1, column2 FROM table2;

UNION ALL

  • Сохраняет все строки, включая дубликаты.
  • Работает быстрее, когда дубликаты заведомо невозможны или не важны.
SELECT name, email FROM customers
UNION ALL
SELECT name, email FROM employees;

Требования к UNION

  • Все SELECT должны возвращать одинаковое количество столбцов.
  • Соответствующие столбцы должны иметь совместимые типы данных.
  • Имена столбцов в итоговой выборке берутся из первого SELECT.
Проверить по документации: в некоторых СУБД для совместимости типов применяется неявное приведение. Перед промышленным использованием уточняйте правила в документации конкретной базы.

📖 Виды соединений JOIN

JOIN объединяет строки из двух или более таблиц на основе логической связи — обычно равенства значений внешнего и первичного ключей.

ОператорЧто возвращаетКогда использовать
INNER JOIN Только строки, имеющие совпадения в обеих таблицах. Нужны только связанные данные, без «пустых» строк.
LEFT JOIN / LEFT OUTER JOIN Все строки левой таблицы + совпадающие строки правой. Если совпадений нет — NULL. Нужно сохранить все строки основной таблицы, даже без связей.
RIGHT JOIN Все строки правой таблицы + совпадающие строки левой. Если совпадений нет — NULL. Редко используется: обычно заменяется LEFT JOIN с перестановкой таблиц.
CROSS JOIN Декартово произведение: каждая строка первой таблицы соединяется с каждой строкой второй. Почти никогда в продакшене из-за огромного результата.
FULL JOIN / FULL OUTER JOIN Все строки обеих таблиц, NULL там, где нет совпадений. Не реализован в MySQL; доступен в PostgreSQL, SQLite и других.

Визуальная аналогия

  • INNER JOIN — пересечение двух множеств.
  • LEFT JOIN — всё левое множество + пересечение.
  • RIGHT JOIN — всё правое множество + пересечение.
  • FULL JOIN — объединение двух множеств.
  • CROSS JOIN — все возможные пары элементов.

📖 Общий синтаксис JOIN

SELECT столбцы
FROM таблица1
INNER JOIN таблица2
  ON таблица1.колонка = таблица2.колонка;
  • таблица1 и таблица2 — таблицы, которые нужно соединить.
  • ON — условие связи. Чаще всего это равенство внешнего ключа одной таблицы первичному ключу другой.
  • Алиасы (AS) делают запрос короче и читабельнее.
SELECT o.id, c.company_name
FROM orders AS o
INNER JOIN customers AS c
  ON o.customer_id = c.id;
Проверить по документации: в MySQL ключевое слово INNER можно опускать: JOIN по умолчанию работает как INNER JOIN. В других СУБД поведение может отличаться.

📖 Соединение более двух таблиц

Если данные разбросаны по трём и более таблицах, можно последовательно добавлять JOIN:

SELECT od.order_id, p.product_name, po.payment_amount
FROM order_details AS od
LEFT JOIN products AS p
  ON od.product_id = p.id
LEFT JOIN purchase_orders AS po
  ON od.purchase_order_id = po.id;

Порядок соединений важен: результат каждого предыдущего JOIN становится «левой» таблицей для следующего.

📖 Примеры на схеме northwind

База northwind используется в занятии для демонстрации. Ключевые таблицы:

  • customers — клиенты (id — первичный ключ).
  • employees — сотрудники (id — первичный ключ).
  • orders — заказы (customer_id ссылается на customers, employee_id — на employees).
  • order_details — строки заказов (order_id, product_id).
  • products — товары (id — первичный ключ).
  • purchase_orders — закупки (id — первичный ключ).
  • invoices — инвойсы (order_id ссылается на orders).

✨ Современные практики

  • Всегда указывайте ON явно. Неявное соединение через запятую в WHERE устарело и легко приводит к декартову произведению.
  • Выбирайте минимально необходимый тип JOIN: если нужны только связанные строки — INNER JOIN, не LEFT JOIN.
  • Используйте UNION ALL, если дубликаты заведомо невозможны: это быстрее и менее ресурсоёмко.
  • Проверяйте индексы на столбцах условий JOIN: без индекса большие таблицы соединяются очень медленно.