Як працює right join?
SQL RIGHT JOIN повертає всі рядки з правої таблиці і тільки ті рядки з лівої, які мають збіг. Де збігу немає, у лівих колонках буде NULL.
Теорія
TL;DR
- Аналогія: кожне замовлення зі списку потрапляє у звіт, дані клієнта підставляються лише там, де є збіг.
- Головна різниця: RIGHT JOIN зберігає всі рядки правої таблиці. INNER JOIN залишає тільки збіги. LEFT JOIN зберігає всі рядки лівої таблиці.
- Правило вибору: права таблиця = основа даних (всі відправлення мають бути у звіті) → RIGHT JOIN. Інакше → LEFT JOIN або INNER JOIN.
A RIGHT JOIN BрівнозначнеB LEFT JOIN A.
Швидкий приклад
CREATE TABLE clients (id INT, name VARCHAR(50));
INSERT INTO clients VALUES (1, 'Alice'), (2, 'Bob');
CREATE TABLE orders (order_id INT, client_id INT, item VARCHAR(50));
INSERT INTO orders VALUES (101, 1, 'Laptop'), (102, NULL, 'Mouse'), (103, 3, 'Keyboard');
-- Всі замовлення у результаті; клієнти підставляються де є збіг
SELECT c.name, o.item
FROM clients c
RIGHT JOIN orders o ON c.id = o.client_id;Результат:
name | item
Alice | Laptop
NULL | Mouse
NULL | KeyboardВсі 3 замовлення у результаті. Замовлення 102 і 103 не мають відповідного клієнта, тому name = NULL.
Ключова різниця
RIGHT JOIN - це дзеркало LEFT JOIN. LEFT залишає всі рядки лівої таблиці і підставляє NULL справа, де збігів немає. RIGHT робить навпаки: кожен рядок правої таблиці зберігається, ліві колонки стають NULL без збігу. На практиці більшість команд переписують RIGHT JOIN як LEFT JOIN зі зміненим порядком таблиць - так основна таблиця стоїть першою і код читається природніше. Оптимізатор запитів виконує обидва варіанти однаково.
Коли використовувати
- Всі рядки правої таблиці мають бути у результаті → RIGHT JOIN (всі відправлення, всі події у логах).
- Всі рядки лівої таблиці мають бути у результаті → LEFT JOIN.
- Тільки збіги важливі → INNER JOIN.
- Все з обох таблиць → FULL OUTER JOIN.
Таблиця порівняння
| Тип з'єднання | Рядки лівої таблиці | Рядки правої таблиці | NULL у | Типовий сценарій |
|---|---|---|---|---|
| INNER JOIN | Тільки збіги | Тільки збіги | Немає | Клієнти з замовленнями |
| LEFT JOIN | Всі | Тільки збіги | Праві колонки | Всі клієнти + їхні замовлення |
| RIGHT JOIN | Тільки збіги | Всі | Ліві колонки | Всі замовлення + дані клієнтів |
| FULL OUTER JOIN | Всі | Всі | Обидві сторони | Повний аудит, злиття даних |
Типові помилки
Помилка: фільтрація NULL через WHERE після RIGHT JOIN
-- Неправильно: перетворює RIGHT JOIN на INNER JOIN
SELECT * FROM clients c
RIGHT JOIN orders o ON c.id = o.client_id
WHERE c.name IS NOT NULL;WHERE виконується після з'єднання. Умова WHERE c.name IS NOT NULL видаляє всі рядки правої таблиці без збігу. Результат стає таким самим як у INNER JOIN. Якщо потрібно фільтрувати ліву таблицю зі збереженням усіх правих рядків, перемісти умову в ON:
-- Правильно: умова в ON, рядки правої таблиці зберігаються
SELECT * FROM clients c
RIGHT JOIN orders o ON c.id = o.client_id AND c.name IS NOT NULL;Помилка: очікування що NULL у ключі з'єднання зникне
Якщо order.client_id є NULL, рядок все одно потрапляє у результат. NULL не дорівнює NULL, збігу немає, і c.name буде NULL. Рядок не видаляється.
Помилка: змішування RIGHT JOIN і LEFT JOIN в одному запиті
FROM clients RIGHT JOIN orders - це те саме що FROM orders LEFT JOIN clients. Більшість команд використовують LEFT JOIN, бо головна таблиця стоїть першою. Коли в одному запиті є і LEFT, і RIGHT JOIN, логіку стає важко відстежувати.
Де зустрічається
- E-commerce: всі відправлення з опціональними даними клієнтів (
shipments RIGHT JOIN customers). - Логування: всі події з опціональними даними сесії, щоб жоден запис не загубився.
- HR-системи: всі записи співробітників з опціональними відділами.
- Аналітика: всі покази реклами з опціональними даними кліків.
Питання на співбесіді
Q: Що буде, якщо ключ з'єднання у правій таблиці NULL?
A: Рядок правої таблиці все одно потрапляє у результат. NULL не дорівнює NULL, збігу немає, ліві колонки = NULL.
Q: Як переписати RIGHT JOIN як LEFT JOIN?
A: Поміняй таблиці місцями і зміни тип з'єднання. FROM A RIGHT JOIN B ON A.id = B.id стає FROM B LEFT JOIN A ON B.id = A.id.
Q: Чому фільтр WHERE на ліву таблицю ламає поведінку RIGHT JOIN?
A: WHERE виконується після з'єднання. WHERE left.col IS NOT NULL видаляє всі рядки правої таблиці без збігу, результат як у INNER JOIN. Для фільтрації лівої таблиці використовуй умову в ON.
Q: У ланцюжку A RIGHT JOIN B RIGHT JOIN C як поширюються NULL?
A: Кожне з'єднання виконується зліва направо. Якщо A не має збігу з B, колонки A стають NULL. Це NULL бере участь у наступному з'єднанні з C. Намалюй два окремих з'єднання щоб побачити як NULL рухається по ланцюжку.
Приклади
Базовий: всі замовлення з опціональними іменами клієнтів
CREATE TABLE clients (id INT, name VARCHAR(50));
INSERT INTO clients VALUES (1, 'Alice'), (2, 'Bob');
CREATE TABLE orders (order_id INT, client_id INT, item VARCHAR(50));
INSERT INTO orders VALUES (101, 1, 'Laptop'), (102, NULL, 'Mouse'), (103, 3, 'Keyboard');
SELECT c.name, o.order_id, o.item
FROM clients c
RIGHT JOIN orders o ON c.id = o.client_id;
-- name | order_id | item
-- Alice | 101 | Laptop
-- NULL | 102 | Mouse <- немає client_id
-- NULL | 103 | Keyboard <- client_id 3 не існуєЗамовлення 102 і 103 не мають відповідного запису у clients. RIGHT JOIN зберігає їх у результаті.
Середній рівень: звіт про відправлення в e-commerce
CREATE TABLE customers (cust_id INT, email VARCHAR(100));
INSERT INTO customers VALUES (1, 'alice@shop.com'), (2, 'bob@shop.com');
CREATE TABLE shipments (ship_id INT, cust_id INT, status VARCHAR(20));
INSERT INTO shipments VALUES
(5001, 1, 'Delivered'),
(5002, NULL, 'Pending'),
(5003, 2, 'Shipped'),
(5004, 3, 'Cancelled');
SELECT s.ship_id, s.status, c.email
FROM customers c
RIGHT JOIN shipments s ON c.cust_id = s.cust_id
ORDER BY s.ship_id;
-- ship_id | status | email
-- 5001 | Delivered | alice@shop.com
-- 5002 | Pending | NULL
-- 5003 | Shipped | bob@shop.com
-- 5004 | Cancelled | NULLВсі 4 відправлення у логістичному звіті. Відправлення 5002 і 5004 не мають зареєстрованого клієнта, але бізнес все одно повинен їх відстежувати. Саме для цього і існує RIGHT JOIN.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.