Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як працює right join?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**SQL RIGHT JOIN** повертає всі рядки правої таблиці і тільки ті рядки лівої, що мають збіг. Ліві колонки без збігу = NULL. ```sql SELECT c.name, o.item FROM clients c RIGHT JOIN orders o ON c.id = o.client_id; -- Alice | Laptop -- NULL | Mouse <- клієнта немає ``` **Ключове:** RIGHT JOIN = LEFT JOIN зі зміненим порядком таблиць.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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`. ### Швидкий приклад ```sql 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** ```sql -- Неправильно: перетворює 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: ```sql -- Правильно: умова в 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 рухається по ланцюжку. ## Приклади ### Базовий: всі замовлення з опціональними іменами клієнтів ```sql 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 ```sql 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.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.