Подсчёт заказов по статусам, показывая 0 для статусов без заказов
Таблицы statuses(id, name) и orders(id, status_id). Верните число заказов по каждому статусу, включая статусы, у которых сейчас нет заказов — они должны показывать 0, а не отсутствовать в результате.
-- число заказов на статус; статусы без заказов показывают 0
Напишите запрос.
Ведут запрос от statuses с LEFT JOIN к orders, чтобы статус без заказа давал строку. COUNT(o.id) — по присоединённому столбцу, а не COUNT(*) — потому что COUNT по NULL несопоставленной стороны даёт 0, а COUNT(*) посчитал бы строку-заполнитель как 1.
- ✗Брать INNER JOIN, который отбрасывает статусы без заказов
- ✗Брать COUNT(*) на outer join и считать строку-заполнитель как 1
- ✗Считать, что пустой скалярный подзапрос вернёт 0, а не NULL
- →Почему COUNT(o.id) даёт 0, а COUNT(*) — 1 для пустого статуса?
- →Как в том же запросе показать ещё и сумму заказов на статус?
Start from statuses so every status is present, LEFT JOIN the orders, and count the joined column.
SELECT s.name,
COUNT(o.id) AS order_count
FROM statuses s
LEFT JOIN orders o ON o.status_id = s.id
GROUP BY s.id, s.name
ORDER BY order_count DESC;
The key subtlety is COUNT(o.id) versus COUNT(*). For a status with no orders the outer join produces a single row with all orders columns NULL. COUNT(o.id) ignores that NULL and returns 0; COUNT(*) counts the row itself and wrongly returns 1. An INNER JOIN would drop the empty statuses entirely.