Какое минимальное и максимальное количество строк может быть после left join?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Количество строк после LEFT JOIN: минимум и максимум
Основной принцип LEFT JOIN
LEFT JOIN сохраняет ВСЕ строки из левой таблицы и добавляет соответствующие строки из правой. Результат всегда >= количество строк в левой таблице.
Минимальное количество строк
Минимум = количество строк в левой таблице
Это происходит, когда:
- Правая таблица пуста
- Условие ON не находит совпадений (строки из левой таблицы остаются с NULL в полях из правой)
- Между таблицами нет дубликатов при объединении
Пример:
-- Левая таблица: 5 строк
SELECT * FROM users
-- id | name
-- 1 | Alice
-- 2 | Bob
-- 3 | Charlie
-- 4 | David
-- 5 | Eve
-- Правая таблица: 2 строки
SELECT * FROM orders
-- id | user_id | amount
-- 101| 1 | 100
-- 102| 2 | 200
-- LEFT JOIN: результат 5 строк (количество юзеров)
SELECT u.id, u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Результат:
-- id | name | amount
-- 1 | Alice | 100
-- 2 | Bob | 200
-- 3 | Charlie | NULL
-- 4 | David | NULL
-- 5 | Eve | NULL
Вывод: хотя в orders только 2 строки, результат имеет 5 строк (как и левая таблица).
Максимальное количество строк
Максимум = количество строк в левой таблице × количество совпадений в правой таблице
Это происходит, когда для каждой строки левой таблицы находится несколько совпадений в правой таблице.
Пример с дубликатами в правой таблице:
-- Левая таблица: 3 строки
SELECT * FROM customers
-- customer_id | name
-- 1 | Alice
-- 2 | Bob
-- 3 | Charlie
-- Правая таблица: 5 строк (дубликаты по customer_id)
SELECT * FROM purchases
-- purchase_id | customer_id | amount
-- 101 | 1 | 100
-- 102 | 1 | 150 <- второй заказ Alice
-- 103 | 1 | 200 <- третий заказ Alice
-- 104 | 2 | 300
-- 105 | 2 | 400 <- второй заказ Bob
-- LEFT JOIN: результат 5 строк!
SELECT c.customer_id, c.name, p.purchase_id, p.amount
FROM customers c
LEFT JOIN purchases p ON c.customer_id = p.customer_id;
-- Результат:
-- customer_id | name | purchase_id | amount
-- 1 | Alice | 101 | 100
-- 1 | Alice | 102 | 150
-- 1 | Alice | 103 | 200
-- 2 | Bob | 104 | 300
-- 2 | Bob | 105 | 400
-- 3 | Charlie | NULL | NULL
Формула: Максимум строк = SUM(количество совпадений для каждой левой строки)
Критические случаи
Случай 1: Дубликаты в левой таблице
-- Левая таблица: 4 строки (дубликат user_id=1)
users:
-- user_id | name
-- 1 | Alice
-- 1 | Alice (дубликат!)
-- 2 | Bob
-- 3 | Charlie
-- Правая таблица: 2 строки
orders:
-- order_id | user_id | amount
-- 101 | 1 | 100
-- 102 | 2 | 200
-- LEFT JOIN результат: 5 строк!
SELECT u.user_id, u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Результат:
-- user_id | name | amount
-- 1 | Alice | 100 <- совпадение для первой Alice
-- 1 | Alice | 100 <- совпадение для дубликата Alice
-- 2 | Bob | 200
-- 3 | Charlie | NULL
-- (5 строк!)
Вывод: дубликаты в левой таблице приводят к дубликатам в результате.
Случай 2: Дубликаты в обеих таблицах
-- Левая: 3 строки (дубликат)
users:
-- id | name
-- 1 | Alice
-- 1 | Alice (дубликат)
-- 2 | Bob
-- Правая: 2 строки (дубликаты)
orders:
-- id | user_id | amount
-- 101| 1 | 100
-- 102| 1 | 150 <- второй заказ user_id=1
-- LEFT JOIN: 4 строки!
SELECT *
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Результат:
-- id | name | id | user_id | amount
-- 1 | Alice | 101 | 1 | 100 <- Alice(1) x order(101)
-- 1 | Alice | 102 | 1 | 150 <- Alice(1) x order(102)
-- 1 | Alice | 101 | 1 | 100 <- Alice(1-дубликат) x order(101)
-- 1 | Alice | 102 | 1 | 150 <- Alice(1-дубликат) x order(102)
-- 2 | Bob | NULL| NULL | NULL
Формула для этого случая:
- Alice(1) в левой: 2 строки
- Заказы для user_id=1: 2 строки
- Результат: 2 × 2 = 4 строки на Alice
- Plus Bob (1 строка) = 5 строк
Случай 3: Составное условие ON
-- Левая: 3 строки
users:
-- id | country
-- 1 | USA
-- 2 | USA
-- 3 | UK
-- Правая: 4 строки
orders:
-- id | user_id | country | amount
-- 101| 1 | USA | 100
-- 102| 1 | USA | 150 <- дубликат для user_id=1, USA
-- 103| 2 | USA | 200
-- 104| 2 | UK | 250 <- разная страна
-- LEFT JOIN с составным условием
SELECT *
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND u.country = o.country;
-- Результат:
-- u.id | u.country | o.id | o.user_id | o.country | amount
-- 1 | USA | 101 | 1 | USA | 100
-- 1 | USA | 102 | 1 | USA | 150 <- совпадает по обоим условиям
-- 2 | USA | 103 | 2 | USA | 200
-- 2 | USA | NULL | NULL | NULL | NULL <- order для user_id=2 имеет UK, не совпадает
-- 3 | UK | NULL | NULL | NULL | NULL <- нет заказов для UK
-- Итого: 5 строк
Чистая математика LEFT JOIN
Минимум строк = количество строк в левой таблице
Максимум строк = количество строк в левой × максимум повторений в правой
Примеры:
| Left rows | Max matches per left row | Result rows |
|---|---|---|
| 10 | 1 | 10-10 |
| 10 | 5 | 10-50 |
| 100 | 2 | 100-200 |
| 1000 | 0 (no matches) | 1000 |
Как узнать максимум совпадений?
-- Проверка дубликатов в правой таблице
SELECT join_key, COUNT(*) as match_count
FROM right_table
GROUP BY join_key
ORDER BY match_count DESC;
-- Если есть join_key с count > 1, то будут дубликаты в результате
Пример:
-- Проверим orders на дубликаты user_id
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
ORDER BY order_count DESC;
-- Результат:
-- user_id | order_count
-- 1 | 3 <- максимум 3 заказа для одного пользователя
-- 2 | 2
-- 5 | 1
-- Итого: левая таблица (users) может иметь до N×3 строк, где N = количество пользователей
Практические советы для аналитика
1. Всегда проверяй дубликаты перед JOIN
-- Проверка дубликатов в обеих таблицах
SELECT
'left' as table_name,
join_key,
COUNT(*) as duplicate_count
FROM left_table
GROUP BY join_key
HAVING COUNT(*) > 1
UNION ALL
SELECT
'right' as table_name,
join_key,
COUNT(*)
FROM right_table
GROUP BY join_key
HAVING COUNT(*) > 1;
2. Использует DISTINCT если нужны уникальные строки
-- Если нужны уникальные пользователи (без дубликатов заказов)
SELECT DISTINCT u.user_id, u.name
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
3. Используй COUNT для проверки результата
-- Сравни количество строк
SELECT COUNT(*) FROM left_table; -- ожидаемый минимум
SELECT COUNT(*) FROM (
SELECT *
FROM left_table l
LEFT JOIN right_table r ON ...
) result; -- фактический результат
4. Внимание на NULL при подсчёте
-- После LEFT JOIN с NULL значениями
SELECT
COUNT(*) as total_rows, -- включает NULL
COUNT(right_id) as non_null_rows, -- исключает NULL
COUNT(*) - COUNT(right_id) as null_rows
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
Заключение
LEFT JOIN ГАРАНТИРУЕТ:
- Минимум: все строки из левой таблицы (никогда не меньше)
- Максимум: все строки из левой × максимум совпадений в правой
Дубликаты в правой таблице — основная причина неожиданного роста строк. Всегда проверяй их перед написанием JOIN!