В чем разница между четыремя основными типами соединений в SQL?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Четыре основных типа 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;
Лучшие практики
- INNER JOIN — когда обе стороны должны существовать (часто)
- LEFT JOIN — когда слева основная таблица (очень часто)
- RIGHT JOIN — редко, используй LEFT с перевёрнутым порядком
- FULL OUTER JOIN — когда нужны все записи (редко, может быть медленно)
- Всегда специфицируй условие JOIN явно (ON clause)
- Используй индексы на join-колонках для производительности
- Понимай типы 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.