Пошук уроків, статей та іншого контенту
Як зібрати дані з кількох пов'язаних таблиць в один результат — INNER, LEFT та різниця між ними.
Реляційна модель (перший урок цього курсу) навмисно розділяє пов'язані дані по різних таблицях замість дублювання — але щоб показати замовлення разом з іменем користувача, який його зробив, потрібно зібрати дані з двох таблиць (users і orders) в один результат. Саме це й робить JOIN — об'єднує рядки двох таблиць за умовою збігу значень (типово — зовнішній ключ, що посилається на первинний ключ іншої таблиці).
SELECT orders.id, orders.total, users.name
FROM orders
INNER JOIN users ON orders.user_id = users.id;INNER JOIN повертає лише ті рядки orders, для яких знайшовся відповідний рядок users за умовою — замовлення без валідного user_id (якщо таке можливо) до результату не потрапить узагалі.
SELECT users.name, orders.id AS order_id
FROM users
LEFT JOIN orders ON orders.user_id = users.id;
-- Користувачі без жодного замовлення теж потраплять у результат,
-- зі значенням NULL у стовпцях ordersLEFT JOIN повертає геть усі рядки лівої (першої вказаної) таблиці — навіть якщо для них немає відповідного рядка в правій таблиці, значення стовпців правої таблиці в такому рядку будуть NULL. Типовий випадок використання — «показати всіх користувачів, включно з тими, хто ще не зробив жодного замовлення».
INNER JOIN — лише рядки з парою в обох таблицях; підходить, коли пов'язаний рядок логічно завжди має існувати або відсутність пари означає, що рядок узагалі не цікавить.
LEFT JOIN — усі рядки лівої таблиці, з NULL там, де пари немає; підходить, коли важливо не втратити рядки лівої таблиці навіть без пов'язаних даних.
RIGHT JOIN — дзеркальний до LEFT (усі рядки правої таблиці) — на практиці рідко потрібен, оскільки той самий результат можна отримати LEFT JOIN, просто помінявши таблиці місцями.
Стаття «N+1 Query Problem» розбирає, як цикл окремих запитів (по одному на кожен рядок списку) замінюють одним запитом з JOIN — саме цей SQL-механізм і стоїть за eager loading в ORM: замість N окремих SELECT-запитів до users по одному на кожне замовлення, один запит із JOIN отримує всі потрібні дані одразу.
JOIN кількох великих таблиць без індексів на стовпцях умови з'єднання (стаття «Індекси в PostgreSQL») може бути повільним — база даних змушена порівнювати кожен рядок однієї таблиці з кожним рядком іншої без індексу, що допоміг би одразу знайти відповідність.
Використання INNER JOIN там, де насправді потрібні рядки лівої таблиці навіть без пари, — рядки без відповідності мовчки зникають із результату замість очікуваного NULL.
Забути умову ON (чи використати CROSS JOIN ненавмисно) — результатом стає декартів добуток усіх можливих комбінацій рядків обох таблиць, що для нетривіальних таблиць є величезним і практично марним результатом.
Не індексувати стовпці, що використовуються в умові JOIN (зазвичай зовнішні ключі), — сповільнює кожен запит, що з'єднує ці таблиці.
JOIN об'єднує рядки двох таблиць за умовою відповідності, найчастіше зовнішнього ключа до первинного. INNER JOIN повертає лише рядки з парою в обох таблицях, LEFT JOIN — усі рядки лівої таблиці незалежно від наявності пари. Саме JOIN — SQL-механізм, що стоїть за вирішенням проблеми N+1 запитів через eager loading в ORM.