Соединения таблиц: JOIN

Соединяем данные из нескольких таблиц и разбираемся, чем отличаются виды JOIN.

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

Данные для примеров

Возьмём клиентов и их заказы. Намеренно сделаем так, чтобы у одного клиента не было заказов, а один заказ был «бесхозным» — на этом будут видны различия JOIN-ов.

CREATE TABLE clients (
    id   INTEGER PRIMARY KEY,
    name TEXT
);
CREATE TABLE orders (
    id        INTEGER PRIMARY KEY,
    client_id INTEGER,
    amount    INTEGER
);

INSERT INTO clients (id, name) VALUES
    (1, 'Анна'), (2, 'Борис'), (3, 'Вера');
INSERT INTO orders (id, client_id, amount) VALUES
    (1, 1, 500), (2, 1, 300), (3, 2, 800), (4, 99, 100);
-- У Веры (id=3) заказов нет. Заказ 4 ссылается на несуществующего клиента 99.

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

Самый частый. Возвращает строки, где совпадение нашлось в обеих таблицах. Несовпавшие отбрасываются.

SELECT c.name, o.amount
FROM clients c
INNER JOIN orders o ON o.client_id = c.id
ORDER BY c.name, o.amount;

Вывод:

Анна|300
Анна|500
Борис|800

Веры нет (у неё нет заказов), бесхозного заказа 4 тоже нет (нет клиента 99). INNER JOIN оставил только полные пары.

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

Возвращает все строки левой таблицы, а из правой подставляет совпадения или NULL, если их нет. Идеален для вопроса «покажи всех клиентов, в том числе без заказов».

SELECT c.name, o.amount
FROM clients c
LEFT JOIN orders o ON o.client_id = c.id
ORDER BY c.name;

Вывод:

Анна|300
Анна|500
Борис|800
Вера|

Теперь Вера попала в результат, а в столбце amount у неё пусто (NULL) — заказов нет, но клиент показан.

RIGHT и FULL JOIN

RIGHT JOIN — зеркало LEFT: все строки правой таблицы. FULL JOIN — все строки обеих таблиц, с NULL там, где пары не нашлось.

JOINЧто возвращает
INNERтолько совпавшие пары
LEFTвсе левые + совпавшие правые (иначе NULL)
RIGHTвсе правые + совпавшие левые (иначе NULL)
FULLвсе строки обеих таблиц

Примечание: SQLite-песочница поддерживает RIGHT и FULL JOIN начиная с современных версий, но если ваш движок их не понимает, RIGHT JOIN A B всегда можно переписать как LEFT JOIN B A.

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

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

SELECT o.id, c.name, p.title
FROM orders o
JOIN clients c  ON c.id = o.client_id
JOIN products p ON p.id = o.product_id;

Итог

  • INNER JOIN оставляет только совпавшие пары — несовпавшие строки исчезают.
  • LEFT JOIN сохраняет все левые строки, подставляя NULL при отсутствии пары справа.
  • RIGHT — зеркало LEFT, FULL — все строки обеих таблиц; JOIN-ы выстраиваются в цепочку.
Проверьте себя
1. Чем LEFT JOIN отличается от INNER JOIN?
AНичем
BLEFT JOIN сохраняет все строки левой таблицы, даже без пары справа (там будет NULL)
CLEFT JOIN быстрее
DLEFT JOIN возвращает только несовпавшие строки
2. Если у клиента нет заказов, что вернёт LEFT JOIN clients к orders в столбце amount?
A0
BПустую строку ''
CNULL
DОшибку
3. Как переписать RIGHT JOIN A B, если движок его не поддерживает?
AINNER JOIN A B
BLEFT JOIN B A
CFULL JOIN A B
DНикак
Поддержать проект