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

Что будет в значениях правой части таблицы, если использовать LEFT JOIN для строк, которых нет в SQL?

1.7 Middle🔥 181 комментариев
#REST API и HTTP

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

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

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

LEFT JOIN и значения для неименяющихся строк

Это фундаментальный вопрос о работе SQL JOIN-ов. Ответ простой: в значениях правой части будут NULL для строк левой таблицы, которые не имеют соответствия в правой таблице.

Как работает LEFT JOIN

LEFT JOIN (или LEFT OUTER JOIN) включает:

  • Все строки из левой таблицы
  • Соответствующие строки из правой таблицы
  • Если для левой строки нет соответствия в правой — значения правой таблицы будут NULL

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

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

users

user_idname
1Alice
2Bob
3Charlie

orders

order_iduser_idamount
1011100
1021200
1032150
import sqlite3

conn = sqlite3.connect(":memory:")
cursor = conn.cursor()

# Создаем таблицы
cursor.execute("""CREATE TABLE users (
    user_id INTEGER PRIMARY KEY,
    name TEXT
)""")

cursor.execute("""CREATE TABLE orders (
    order_id INTEGER PRIMARY KEY,
    user_id INTEGER,
    amount INTEGER
)""")

# Вставляем данные
cursor.executemany("INSERT INTO users VALUES (?, ?)", [
    (1, "Alice"),
    (2, "Bob"),
    (3, "Charlie")
])

cursor.executemany("INSERT INTO orders VALUES (?, ?, ?)", [
    (101, 1, 100),
    (102, 1, 200),
    (103, 2, 150)
])

conn.commit()

# LEFT JOIN: все пользователи + их заказы (если они есть)
cursor.execute("""
    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
    ORDER BY u.user_id
""")

results = cursor.fetchall()
for row in results:
    print(row)

conn.close()

Вывод:

(1, 'Alice', 101, 100)
(1, 'Alice', 102, 200)
(2, 'Bob', 103, 150)
(3, 'Charlie', None, None)  # ← Charlie не имеет заказов!

Заметьте: для Charlie (user_id=3) в правой части (orders) значения NULL, потому что у него нет заказов.

Визуальное объяснение

LEFT JOIN: u LEFT JOIN o

users    orders
user_id | name    | order_id | user_id | amount
--------|---------|----------|---------|-------
  1     | Alice   | 101      | 1       | 100    ✓ Match
  1     | Alice   | 102      | 1       | 200    ✓ Match
  2     | Bob     | 103      | 2       | 150    ✓ Match
  3     | Charlie | NULL     | NULL    | NULL   ✗ No match
                    ↑
              Значения из правой таблицы = NULL

Проверка NULL значений

При работе с LEFT JOIN результаты нужно проверять на NULL:

import sqlite3

conn = sqlite3.connect(":memory:")
cursor = conn.cursor()

# Тот же пример...
# ... (создание таблиц и вставка данных как выше)

cursor.execute("""
    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
""")

for user_id, name, order_id, amount in cursor.fetchall():
    if order_id is None:
        print(f"{name} не имеет заказов")
    else:
        print(f"{name} имеет заказ #{order_id} на сумму {amount}")

Вывод:

Alice имеет заказ #101 на сумму 100
Alice имеет заказ #102 на сумму 200
Bob имеет заказ #103 на сумму 150
Charlie не имеет заказов

INNER JOIN vs LEFT JOIN

INNER JOIN — только строки с соответствиями:

cursor.execute("""
    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
""")
# Результат:
# (1, 'Alice', 101, 100)
# (1, 'Alice', 102, 200)
# (2, 'Bob', 103, 150)
# Charlie НЕ ВКЛЮЧЕН, так как у него нет заказов

LEFT JOIN — все из левой, плюс соответствия:

cursor.execute("""
    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
""")
# Результат:
# (1, 'Alice', 101, 100)
# (1, 'Alice', 102, 200)
# (2, 'Bob', 103, 150)
# (3, 'Charlie', None, None)  ← Charlie включен с NULL

RIGHT JOIN и FULL OUTER JOIN

RIGHT JOIN — наоборот (все из правой таблицы):

# Все заказы, даже если нет соответствующего пользователя
cursor.execute("""
    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
""")

FULL OUTER JOIN (поддерживается не всеми БД) — все строки из обеих таблиц:

cursor.execute("""
    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
""")
# Содержит AND:
# - Строки только из users (с NULL в orders) 
# - Строки только из orders (с NULL в users)
# - Совпадающие строки из обеих таблиц

Часто встречаемые ошибки

❌ Плохо: забыл про NULL

cursor.execute("""
    SELECT u.user_id, u.name, COUNT(o.order_id)
    FROM users u
    LEFT JOIN orders o ON u.user_id = o.user_id
    GROUP BY u.user_id
""")
# Charlie будет иметь COUNT = 0, что правильно
# Но нужно помнить, что order_id = NULL!

✅ Хорошо: правильная обработка NULL

cursor.execute("""
    SELECT u.user_id, u.name, 
           COALESCE(COUNT(o.order_id), 0) as order_count
    FROM users u
    LEFT JOIN orders o ON u.user_id = o.user_id
    GROUP BY u.user_id
""")

for user_id, name, order_count in cursor.fetchall():
    print(f"{name}: {order_count} orders")

Заключение

При использовании LEFT JOIN строкам левой таблицы, которые не имеют соответствия в правой таблице, присваиваются NULL значения для всех столбцов правой таблицы. Это ключевая особенность LEFT JOIN, которая позволяет находить "сироты" (пользователей без заказов, статьи без комментариев и т.д.).

Что будет в значениях правой части таблицы, если использовать LEFT JOIN для строк, которых нет в SQL? | PrepBro