Подсчёт с LEFT JOIN
С LEFT JOIN можно считать даже то, у чего вообще нет пары. Сколько заказов сделал каждый клиент, включая клиентов, не сделавших ни одного?
SELECT c.name, COUNT(*) AS row_count, COUNT(o.id) AS order_count
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY order_count, c.name;| name | row_count | order_count |
|---|---|---|
| Henry Scott | 1 | 0 |
| Max Baker | 1 | 0 |
| Isla Young | 1 | 1 |
| Ava Green | 2 | 2 |
| … | … | … |
Посмотрите на Henry Scott: COUNT(*) показывает 1, а COUNT(o.id) — 0. Почему? COUNT(*) считает строки, а LEFT JOIN дал Henry одну строку — с NULL в столбцах orders. COUNT(o.id) считает только значения, не равные NULL (вы знаете это из урока о группировке), а в единственной строке Henry o.id равен NULL. Поэтому он показывает 0, и это правильный ответ. У Isla Young один настоящий заказ и 1 в обоих столбцах.
Поэтому, когда вы считаете пары после LEFT JOIN, не используйте COUNT(*). Считайте столбец правой таблицы, который никогда не равен NULL в настоящей паре, тот самый, который вы проверяли бы с помощью IS NULL: её первичный ключ или столбец с NOT NULL.
SUM, AVG, MIN и MAX тоже пропускают NULL, а для группы, где одни NULL, они дают NULL, а не 0. Деньги, потраченные клиентом без заказов, получились бы равными NULL. Если нужен 0, используйте COALESCE из урока о функциях: COALESCE(SUM(i.quantity * i.price), 0).
Типичная ошибка — подсчёт с обычным JOIN. Клиенты без заказов пропадают до GROUP BY, поэтому в результате нет ни одного нуля, и ничто не подсказывает, что кого-то не хватает.
Задание
- 1
Для каждой игры покажите, сколько у неё отзывов:
titleи число какreview_count. Игры без отзывов должны быть в результате с 0. Отсортируйте строки поreview_count, затем поtitle:title review_count Castle Siege 0 Lost Temple 0 Mystery Manor 0 Robot Rebellion 0 Bakery Story 1 … … - 2
Ниже покажите, сколько экземпляров каждой игры заказали клиенты, включая возвращённые заказы:
titleи сумму количеств какcopies. Для игр, которые никто не заказывал,copiesдолжно быть 0, а не NULL. Отсортируйте строки поcopies, затем поtitle:title copies Lost Temple 0 Mystery Manor 0 Robot Rebellion 0 Castle Siege 1 Goal Rush 2 Ice Hockey Pro 2 Ocean Deep 2 Star Pilots 2 … …