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

В чем разница между четыремя основными типами соединений в SQL?

1.8 Middle🔥 241 комментариев
#Базы данных (SQL)

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

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

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

# Четыре основных типа JOIN в SQL

Что такое JOIN?

JOIN — это операция, которая объединяет строки из двух или более таблиц на основе связи между ними (обычно по внешнему ключу).

Четыре основных типа: INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN.

1. INNER JOIN (Внутреннее соединение)

INNER JOIN возвращает только строки, которые есть в обеих таблицах.

Если в левой таблице есть запись без соответствия в правой — она не вернётся.

Синтаксис:

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

-- Или просто JOIN (по умолчанию INNER):
SELECT users.id, users.name, orders.order_id
FROM users
JOIN orders ON users.id = orders.user_id;

Пример данных и результат:

Таблица users:          Таблица orders:
id | name              user_id | order_id | amount
1  | Alice             1       | 101      | 50
2  | Bob               1       | 102      | 75
3  | Charlie           3       | 103      | 100

Результат INNER JOIN:
id | name    | order_id | amount
1  | Alice   | 101      | 50        ← Alice в users И в orders
1  | Alice   | 102      | 75        ← Alice в users И в orders
3  | Charlie | 103      | 100       ← Charlie в users И в orders

(Bob отсутствует — нет его в orders)

Python пример (SQLAlchemy):

from sqlalchemy import create_engine, select
from sqlalchemy.orm import Session

engine = create_engine('postgresql://...')

with Session(engine) as session:
    # INNER JOIN
    query = (
        select(User, Order)
        .join(Order, User.id == Order.user_id)  # INNER по умолчанию
    )
    results = session.execute(query).all()
    
    for user, order in results:
        print(f"{user.name} ordered {order.amount}")

2. LEFT JOIN (Левое соединение)

LEFT JOIN возвращает все строки из левой таблицы + совпадающие строки из правой таблицы.

Если справа нет совпадения — значения будут NULL.

Синтаксис:

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

-- Синоним: LEFT OUTER JOIN

Пример данных и результат:

Таблица users:          Таблица orders:
id | name              user_id | order_id | amount
1  | Alice             1       | 101      | 50
2  | Bob               1       | 102      | 75
3  | Charlie           3       | 103      | 100

Результат LEFT JOIN:
id | name    | order_id | amount
1  | Alice   | 101      | 50        ← Alice в orders
1  | Alice   | 102      | 75        ← Alice в orders (вторая запись)
2  | Bob     | NULL     | NULL      ← Bob НЕ в orders — NULL
3  | Charlie | 103      | 100       ← Charlie в orders

Python пример:

from sqlalchemy import select
from sqlalchemy.orm import Session

with Session(engine) as session:
    # LEFT JOIN
    query = (
        select(User, Order)
        .outerjoin(Order, User.id == Order.user_id)  # Все users, и orders где совпадает
    )
    results = session.execute(query).all()
    
    for user, order in results:
        if order:
            print(f"{user.name} ordered {order.amount}")
        else:
            print(f"{user.name} has no orders")  # Bob

3. RIGHT JOIN (Правое соединение)

RIGHT JOIN возвращает все строки из правой таблицы + совпадающие строки из левой таблицы.

Обратное LEFT JOIN. Если слева нет совпадения — значения будут NULL.

Синтаксис:

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

-- Синоним: RIGHT OUTER JOIN

Пример данных и результат:

Таблица users:          Таблица orders:
id | name              user_id | order_id | amount
1  | Alice             1       | 101      | 50
2  | Bob               1       | 102      | 75
3  | Charlie           3       | 103      | 100

Результат RIGHT JOIN (все order, и users где совпадает):
id | name    | order_id | amount
1  | Alice   | 101      | 50        ← user 1 в both
1  | Alice   | 102      | 75        ← user 1 в both (вторая запись)
3  | Charlie | 103      | 100       ← user 3 в both

(Все orders есть, потому что это RIGHT JOIN от orders)

Python примечание:

SQLAlchemy не поддерживает RIGHT JOIN напрямую (но PostgreSQL поддерживает):

# Вместо RIGHT JOIN используй LEFT JOIN с перевёрнутым порядком таблиц
# RIGHT JOIN orders ... ≈ LEFT JOIN users ... (с перевёрнутым порядком)

4. FULL OUTER JOIN (Полное внешнее соединение)

FULL OUTER JOIN возвращает все строки из обеих таблиц.

Если записи совпадают — объединены. Если нет — NULL с обеих сторон.

Синтаксис:

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

Пример данных и результат:

Таблица users:          Таблица orders:
id | name              user_id | order_id | amount
1  | Alice             1       | 101      | 50
2  | Bob               1       | 102      | 75
3  | Charlie           3       | 103      | 100
                        4       | 104      | 200 ← order без user

Результат FULL OUTER JOIN:
id | name    | order_id | amount
1  | Alice   | 101      | 50        ← в обеих таблицах
1  | Alice   | 102      | 75        ← в обеих таблицах
2  | Bob     | NULL     | NULL      ← только в users
3  | Charlie | 103      | 100       ← в обеих таблицах
NULL| NULL   | 104      | 200       ← только в orders (user_id = 4, которого нет)

Python пример:

from sqlalchemy import select, and_
from sqlalchemy.orm import Session

with Session(engine) as session:
    # FULL OUTER JOIN (PostgreSQL поддерживает, SQLite нет)
    query = (
        select(User, Order)
        .outerjoin(Order, User.id == Order.user_id, full=True)  # SQLAlchemy 2.0+
    )
    
    # Или использовать raw SQL:
    result = session.execute(
        "SELECT users.id, users.name, orders.order_id, orders.amount "
        "FROM users "
        "FULL OUTER JOIN orders ON users.id = orders.user_id"
    )

Таблица сравнения

ТипОписаниеВозвращаетПример использования
INNER JOINТолько совпадения в обеихСтроки, которые есть в обеих таблицахЗаказы пользователей (оба должны существовать)
LEFT JOINВсе из левой + совпадения справаВсе левые + NULL справаВсе пользователи + их заказы (если есть)
RIGHT JOINВсе из правой + совпадения слеваВсе правые + NULL слеваВсе заказы + их пользователи (если существуют)
FULL OUTER JOINВсе из обеих + совпаденияВсе записи из обеих таблицПолный отчёт: все пользователи и все заказы

Визуальное представление (Диаграммы Венна)

Таблица A  |  Таблица B
   1,2,3   |    2,3,4

INNER JOIN:          LEFT JOIN:          RIGHT JOIN:       FULL OUTER JOIN:
     [2,3]           [1,2,3]             [2,3,4]           [1,2,3,4]
      ↓                ↓                   ↓                   ↓
  Совпадения      A + совпадения      B + совпадения        A ∪ B

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

Пример 1: Найти заказы с информацией о пользователях

-- ✅ INNER JOIN — только заказы существующих пользователей
SELECT u.name, COUNT(o.id) as order_count
FROM users u
INNER JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;

Пример 2: Показать всех пользователей с количеством их заказов (включая тех, кто не делал заказы)

-- ✅ LEFT JOIN — все пользователи, даже без заказов
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY order_count DESC;

Пример 3: Найти заказы, которые не привязаны к пользователям (ошибки в данных)

-- ✅ RIGHT JOIN или FULL OUTER JOIN с WHERE
SELECT o.id, o.amount, u.name
FROM users u
FULL OUTER JOIN orders o ON u.id = o.user_id
WHERE u.id IS NULL;  -- Заказы без пользователей

Пример 4: Полный отчёт

-- ✅ FULL OUTER JOIN — все записи из обеих таблиц
SELECT 
    COALESCE(u.id, o.user_id) as user_id,
    u.name,
    o.id as order_id,
    o.amount
FROM users u
FULL OUTER JOIN orders o ON u.id = o.user_id
ORDER BY user_id, order_id;

Лучшие практики

  1. INNER JOIN — когда обе стороны должны существовать (часто)
  2. LEFT JOIN — когда слева основная таблица (очень часто)
  3. RIGHT JOIN — редко, используй LEFT с перевёрнутым порядком
  4. FULL OUTER JOIN — когда нужны все записи (редко, может быть медленно)
  5. Всегда специфицируй условие JOIN явно (ON clause)
  6. Используй индексы на join-колонках для производительности
  7. Понимай типы NULL в результатах
# SQLAlchemy пример со всеми типами
from sqlalchemy import select
from sqlalchemy.orm import Session

with Session(engine) as session:
    # INNER — стандарт
    inner = select(User).join(Order)
    
    # LEFT — с выбором всех левых
    left = select(User).outerjoin(Order)
    
    # FULL OUTER — в PostgreSQL
    full = session.execute(
        "SELECT * FROM users FULL OUTER JOIN orders ON users.id = orders.user_id"
    )

Заключение

  • INNER JOIN — совпадения (пересечение)
  • LEFT JOIN — все слева + совпадения справа (левая доля объединения)
  • RIGHT JOIN — все справа + совпадения слева (правая доля объединения)
  • FULL OUTER JOIN — всё из обеих (полное объединение)

В 80% случаев вам нужны INNER и LEFT JOIN.