LEFT JOIN незаметно ведёт себя как INNER JOIN — фильтр правой таблицы в WHERE. Исправьте.
Этот запрос должен выводить каждого клиента с суммой его завершённых заказов, сохраняя клиентов без таковых (amount NULL). Вместо этого он отбрасывает каждого клиента без завершённого заказа — LEFT JOIN ведёт себя как INNER JOIN.
SELECT c.customer_id, o.amount
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.status = 'completed';
Найдите и исправьте ошибку, не потеряв ни одного клиента.
Условие WHERE o.status = 'completed' идёт после join и убирает NULL-дополненные строки, поэтому LEFT JOIN схлопывается в INNER JOIN. Перенесите фильтр правой таблицы в join: LEFT JOIN orders o ON o.customer_id = c.customer_id AND o.status = 'completed'.
- ✗Фильтровать правую таблицу в WHERE после LEFT JOIN
- ✗Винить слово LEFT JOIN, а не момент WHERE
- ✗Думать, что ON ссылается лишь на столбцы ключа join
- →Когда фильтр правой таблицы в WHERE всё же уместен?
- →Чем проверка IS NULL в WHERE отличается от переноса в ON?
The LEFT JOIN produces NULL-padded rows for customers with no matching order. But WHERE runs after the join, and o.status = 'completed' is NULL (not 'completed') on those padded rows, so they fail the filter and disappear — the query effectively becomes an inner join.
Move the right-table condition into the join predicate so it is applied while matching, not after:
SELECT c.customer_id, o.amount
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.customer_id
AND o.status = 'completed'
ORDER BY c.customer_id;
Now every customer is kept: those with a completed order show its amount, and those without show NULL. Rule of thumb — for a preserved (outer) side, put filters on the optional table in ON; keep filters on the preserved table in WHERE.