← Назад к вопросам

В чем разница между INNER JOIN, LEFT JOIN, RIGHT JOIN и FULL OUTER JOIN?

1.0 Junior🔥 181 комментариев
#SQL и базы данных

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Типы JOIN в SQL: полное объяснение

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

Визуальное представление

Представим две таблицы:

Таблица users:

user_id | name
--------|-------
1       | Alice
2       | Bob
3       | Charlie

Таблица orders:

order_id | user_id | amount
---------|---------|--------
101      | 1       | 100
102      | 2       | 200
103      | 4       | 300

Обратите внимание: user_id=4 существует в orders, но не в users!

1. INNER JOIN

Определение: возвращает только строки, которые найдены в ОБЕИХ таблицах.

SELECT u.user_id, u.name, o.order_id, o.amount
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;

Результат:

user_id | name    | order_id | amount
--------|---------|----------|--------
1       | Alice   | 101      | 100
2       | Bob     | 102      | 200

Что произошло:

  • user_id=3 (Charlie) не в orders → исключен
  • order_id=103 (user_id=4) не в users → исключен
  • Только совпадающие: 1, 2

Когда использовать: когда нужны только полные пары данных (например, пользователи, которые совершили покупку).

2. LEFT JOIN (LEFT OUTER JOIN)

Определение: возвращает ВСЕ строки из левой таблицы и совпадающие из правой. Несовпадающие строки в правой таблице замещаются NULL.

SELECT u.user_id, u.name, o.order_id, o.amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;

Результат:

user_id | name    | order_id | amount
--------|---------|----------|--------
1       | Alice   | 101      | 100
2       | Bob     | 102      | 200
3       | Charlie | NULL     | NULL

Что произошло:

  • ALL users остаются (1, 2, 3)
  • Charlie не имеет заказа → NULL
  • order_id=103 исключён (не из левой таблицы)

Когда использовать: чтобы видеть все пользователи и их заказы (если они есть). Идеально для "Найти пользователей, у которых нет заказов".

SELECT u.user_id, u.name
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;  -- Пользователи БЕЗ заказов

3. RIGHT JOIN (RIGHT OUTER JOIN)

Определение: возвращает ВСЕ строки из правой таблицы и совпадающие из левой. Противоположность LEFT JOIN.

SELECT u.user_id, u.name, o.order_id, o.amount
FROM users u
RIGHT JOIN orders o ON u.user_id = o.user_id;

Результат:

user_id | name  | order_id | amount
--------|-------|----------|--------
1       | Alice | 101      | 100
2       | Bob   | 102      | 200
4       | NULL  | 103      | 300

Что произошло:

  • ALL orders остаются (101, 102, 103)
  • user_id=3 (Charlie) исключён (нет его в orders)
  • order_id=103 от неизвестного user_id=4 → NULL в name

Когда использовать: редко. RIGHT JOIN можно заменить LEFT JOIN, переставив таблицы местами.

-- Это эквивалентно:
SELECT o.user_id, u.name, o.order_id, o.amount
FROM orders o
LEFT JOIN users u ON o.user_id = u.user_id;

4. FULL OUTER JOIN (FULL JOIN)

Определение: возвращает ВСЕ строки из обеих таблиц. Несовпадающие замещаются NULL.

SELECT u.user_id, u.name, o.order_id, o.amount
FROM users u
FULL OUTER JOIN orders o ON u.user_id = o.user_id;

Результат:

user_id | name    | order_id | amount
--------|---------|----------|--------
1       | Alice   | 101      | 100
2       | Bob     | 102      | 200
3       | Charlie | NULL     | NULL
4       | NULL    | 103      | 300

Что произошло:

  • ALL пользователи (1, 2, 3)
  • ALL заказы (101, 102, 103)
  • Charlie нет в orders → NULL
  • order_id=103 от unknown user → NULL

Когда использовать: когда нужны оба набора данных полностью. Редко в product analytics.

Сравнительная таблица

JOIN типLEFT таблицаMATCHRIGHT таблицаПример результата
INNERТолько совпадающие
LEFT✓/NULLВсе левые + совпадение
RIGHT✓/NULLВсе правые + совпадение
FULLВсё, но отдельные

Практические примеры в product analytics

1. Найти пользователей БЕЗ покупок

SELECT u.user_id, u.name
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.user_id IS NULL;  -- Не купили

2. Найти заказы от неизвестных пользователей

SELECT o.order_id, o.user_id, u.name
FROM orders o
LEFT JOIN users u ON o.user_id = u.user_id
WHERE u.user_id IS NULL;  -- Заказ от несуществующего user_id

Это может указывать на ошибку в данных!

3. Сравнить активность в двух периодах

SELECT 
  COALESCE(p1.user_id, p2.user_id) as user_id,
  p1.events as events_period1,
  p2.events as events_period2
FROM period1_users p1
FULL OUTER JOIN period2_users p2 ON p1.user_id = p2.user_id;

4. Анализ funnel: кто просмотрел, но не купил

SELECT 
  v.user_id,
  COUNT(v.view_id) as views,
  COUNT(o.order_id) as orders
FROM page_views v
LEFT JOIN orders o ON v.user_id = o.user_id
GROUP BY v.user_id
HAVING COUNT(o.order_id) = 0;  -- Просмотрел, но не купил

Производительность

INNER JOIN — самый быстрый (меньше данных) LEFT/RIGHT JOIN — медленнее (больше данных) FULL OUTER JOIN — самый медленный

Ошибки при использовании

Ошибка 1: забыть ON условие

-- Неправильно: это создаст cartesian product!
SELECT * FROM users u, orders o;

-- Правильно:
SELECT * FROM users u JOIN orders o ON u.user_id = o.user_id;

Ошибка 2: использовать WHERE вместо ON для фильтрации

-- Проблема: LEFT JOIN + WHERE отсеивает NULL
SELECT *
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.amount > 100;  -- Это превращает LEFT в INNER!

-- Правильно:
SELECT *
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.amount > 100;

Ошибка 3: неправильный порядок для RIGHT JOIN

-- Сложно понять:
SELECT * FROM users u RIGHT JOIN orders o ...

-- Лучше:
SELECT * FROM orders o LEFT JOIN users u ...

Роль Product Analyst

Product Analyst часто использует:

  • LEFT JOIN — 80% случаев (найти всех пользователей + данные о них)
  • INNER JOIN — 15% (только полные пары)
  • FULL OUTER JOIN — 5% (редко)

Освоение JOIN — критичный навык для любого аналитика, работающего с SQL.

В чем разница между INNER JOIN, LEFT JOIN, RIGHT JOIN и FULL OUTER JOIN? | PrepBro