Соединения и группы
Соединения и GROUP BY хорошо работают вместе: соединение собирает данные нескольких таблиц в строки, а GROUP BY подводит им итог. Сколько экземпляров игр каждого жанра заказали клиенты? Количества лежат в order_items, жанры — в games:
SELECT g.genre, SUM(i.quantity) AS copies
FROM order_items AS i
JOIN games AS g ON i.game_id = g.id
GROUP BY g.genre
ORDER BY copies DESC, g.genre;| genre | copies |
|---|---|
| Action | 8 |
| RPG | 7 |
| Strategy | 7 |
| … | … |
Соединение даёт строку для каждой позиции вместе с жанром её игры. Затем GROUP BY создаёт группу для каждого жанра, а SUM складывает количества в каждой группе.
С деньгами то же самое. Позиция принесла своё количество, умноженное на цену, которую клиент заплатил за один экземпляр: i.quantity * i.price. Не g.price: это цена в каталоге, а на распродаже клиенты платят меньше. Деньги, которые принесла группа, её выручка, — это тогда SUM(i.quantity * i.price): SUM вычисляет выражение для каждой строки группы и складывает результаты.
Когда вы группируете по тому, у чего есть имя, например по клиенту или игре, группируйте по его id и добавляйте имя в GROUP BY тоже: GROUP BY c.id, c.name. У двух клиентов может быть одно и то же имя, и один только GROUP BY c.name объединил бы их в одну группу, как будто это один человек. Благодаря имени в GROUP BY его можно показать в SELECT: у каждой группы один id, значит, и одно имя. Сколько отзывов написал каждый клиент и сколько звёзд он ставит в среднем?
SELECT c.name, COUNT(*) AS review_count, ROUND(AVG(r.stars), 1) AS average
FROM reviews AS r
JOIN customers AS c ON r.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY review_count DESC, c.name;| name | review_count | average |
|---|---|---|
| Emma Clark | 5 | 4.4 |
| Ava Green | 2 | 3.5 |
| Grace Hall | 2 | 3.5 |
| … | … | … |
Возвращённый заказ ничего не принёс, поэтому выручка должна учитывать только оплаченные заказы. Статус лежит в orders: соедините и эту таблицу, а с помощью WHERE оставьте только оплаченные заказы. WHERE выполняется до GROUP BY, поэтому строки возвращённых заказов исчезают до того, как что-либо складывается. HAVING же выбирает группы, как вы знаете из урока о группировке.
Типичная ошибка — SUM(quantity * price) без псевдонимов. Когда в запросе есть games, price неоднозначен, и вы получаете ошибку. SUM(i.quantity * g.price) хуже: он выполняется, но складывает цены из каталога, и распродажа пропадает из выручки.
Задание
- 1
Покажите выручку каждой игры от оплаченных заказов:
titleи выручку какrevenue. Понадобятся три таблицы:order_items,orders(ради статуса) иgames. Отсортируйте игры по выручке от большей к меньшей, затем по названию:title revenue Knight's Oath 180 Dragon Forge 160 Goal Rush 100 Ice Hockey Pro 90 Turbo Karts 90 Zombie Town 80 … … - 2
Ниже покажите, сколько оплаченных заказов сделал каждый клиент:
nameи число заказов какorder_count, отсортированные поorder_countот большего к меньшему, затем поname:name order_count Emma Clark 4 Olivia Brown 4 Liam Turner 3 Noah Wilson 3 Ava Green 2 … … - 3
А какие клиенты потратили в оплаченных заказах больше 100 долларов? Покажите
nameи потраченные деньги какspent, только для клиентов, потративших больше 100. Отсортируйте поspentот большего к меньшему, затем поname:name spent Emma Clark 200 Liam Turner 150 Noah Wilson 150 Olivia Brown 150