Соединение таблиц

Соединение трёх и более таблиц

Содержание курса

Разберём, как соединить три таблицы в SQL и проследить, откуда берётся каждая строка результата.

Синтаксис двух JOIN подряд и логика цепочки соединений

Представьте, что нужно получить даты заказов, названия купленных товаров и количество единиц. Эти данные лежат в трёх таблицах: orders, order_items и products. Прямой связи между заказом и товаром нет: её хранит промежуточная таблица order_items. Такая цепочка описывается двумя JOIN подряд:

SELECT o.order_date, p.title, oi.quantity
FROM orders AS o
JOIN order_items AS oi ON o.order_id = oi.order_id
JOIN products AS p ON oi.product_id = p.product_id;

Первый JOIN прикрепляет позиции заказа к orders по условию o.order_id = oi.order_id. На этом шаге каждая строка результата описывает одну позицию конкретного заказа. Второй JOIN добавляет сведения о товаре по условию oi.product_id = p.product_id. Он опирается на oi.product_id — столбец таблицы, которая уже находится в цепочке.

Здесь ключевое правило: каждое условие ON связывает новую таблицу с теми, что уже упомянуты выше. Написать ON p.product_id = o.order_id синтаксически допустимо, но это сопоставит разные сущности и даст случайные пары либо пустой результат.

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

Если к этой цепочке нужно добавить клиента, перед order_items появляется ещё один JOIN: customers → orders → order_items → products. Число JOIN само по себе не говорит о плохой схеме. Проверять нужно другое: понятна ли цепочка ключей, верна ли кратность связей, не дублируется ли логика и что показывает план выполнения.

Как меняются строки после каждого JOIN

У заказа №1 две позиции: товар №10 в количестве 2 и товар №20 в количестве 1. В справочнике товаров №10 — клавиатура, №20 — мышь.

ЭтапСтроки результата
orders1 · 2026-11-01
orders JOIN order_items1 · 2026-11-01 · 10 · 2
1 · 2026-11-01 · 20 · 1
Ещё JOIN products2026-11-01 · Клавиатура · 2
2026-11-01 · Мышь · 1

После первого соединения заказ занимает две строки, потому что в нём две позиции. Второе соединение добавляет названия товаров. Здесь ключ products.product_id уникален, поэтому строк больше не становится.

Этот пример можно запустить отдельно в SQLite — данные уже заданы через CTE:

WITH orders(order_id, order_date) AS (VALUES (1, '2026-11-01')),
order_items(order_id, product_id, quantity) AS (VALUES (1, 10, 2), (1, 20, 1)),
products(product_id, title) AS (VALUES (10, 'Клавиатура'), (20, 'Мышь'))
SELECT o.order_date, p.title, oi.quantity
FROM orders AS o
JOIN order_items AS oi ON o.order_id = oi.order_id
JOIN products AS p ON oi.product_id = p.product_id
ORDER BY p.product_id;

Результат — две строки из последней строки таблицы выше. Если справочник содержит несколько записей с одним product_id, JOIN размножит соответствующую позицию заказа; дальше в уроке разберём, как это влияет на суммы.

Начать заново?

Помощник начнёт новый диалог по этой задаче. Текущая переписка останется в истории до конца срока хранения.

О переписке

Можно приложить до трёх фото PNG, JPEG или WebP по 5 МБ.

Переписка и фото хранятся 90 дней после последнего принятого сообщения. Преподаватель получит доступ к диалогу, когда вы попросите его помочь.

Проверка решения остаётся отдельным действием.