Привет! На связи Вячеслав Потапов, ментор курса «Аналитик данных» 👋
Сегодня решил дать вам разбор ошибок, которые можно часто допускать в начале карьеры: почему
LEFT JOIN внезапно превращается в INNER JOIN?Это важно, если вы считаете конверсии, retention, воронки и пользователей без действий (0 заказов, 0 оплат и т. д.).
Задача: есть таблицы:
🟠
users: user_id, registration_date;🟠
orders: order_id, user_id, order_date.Хотим посчитать количество заказов на каждого пользователя после 1 января 2025 года, включая тех, у кого 0 заказов. Как это можно сделать?
select
u.user_id,
count(o.order_id) as orders_cnt
from users u
left join orders o
on u.user_id = o.user_id
where o.order_date >= '2025-01-01'
group by u.user_id;
На вид всё логично, но пользователи без заказов пропадают. Почему так происходит?
LEFT JOIN сохраняет всех пользователей, WHERE o.order_date >= ... выполняется после JOIN. Для пользователей без заказов:➖
o.order_date = NULL;➖ Условие
NULL >= '2025-01-01' даёт NULL;➖ А
WHERE оставляет только TRUE.В результате
LEFT JOIN превращается в INNER JOIN, и часть данных исчезает. Как правильно?Способ 1 (самый правильный) — условие переносим в JOIN:
select
u.user_id,
count(o.order_id) as orders_cnt
from users u
left join orders o
on u.user_id = o.user_id
and o.order_date >= '2025-01-01'
group by u.user_id;
Теперь пользователи без заказов останутся и
count(o.order_id) даст 0.Способ 2 (на больших данных самый надёжный) — агрегируем до JOIN:
with orders_cnt as (
select
user_id,
count(*) as cnt
from orders
where order_date >= '2025-01-01'
group by user_id
)
select
u.user_id,
coalesce(o.cnt, 0) as orders_cnt
from users u
left join orders_cnt o
on u.user_id = o.user_id;
Запомните правило:
WHERE на правой таблице после LEFT JOIN — это опасно. Проверяйте логику — через фильтры для правой таблицы в ON либо через предварительную агрегацию.Ставьте реакции, если было полезно!
📊 Simulative