Запрос к результату
В конце первого урока вы читали, что результат запроса — тоже таблица. Значит, к нему можно обращаться с запросом: поставьте подзапрос в FROM, туда, где стояло бы имя таблицы.
Сколько в среднем стоит заказ? В таблице order_items есть строка на каждую игру в заказе, поэтому сначала нужна сумма каждого заказа:
SELECT order_id, SUM(quantity * price) AS total
FROM order_items
GROUP BY order_id;| order_id | total |
|---|---|
| 1 | 25 |
| 2 | 35 |
| 3 | 40 |
| … | … |
Потом — среднее из этих сумм. AVG(SUM(quantity * price)) не работает, потому что агрегатные функции нельзя вкладывать друг в друга: получится misuse of aggregate function SUM(). Но можно вычислить суммы в подзапросе, а их среднее — во внешнем запросе:
SELECT ROUND(AVG(total), 2) AS average_order
FROM (
SELECT order_id, SUM(quantity * price) AS total
FROM order_items
GROUP BY order_id
) AS totals;| average_order |
|---|
| 42.0 |
Подзапрос выполняется первым и создаёт временную таблицу из 30 строк, по одной на заказ, со столбцами order_id и total. Внешний запрос обращается с ней как с любой другой таблицей: может фильтровать её строки, группировать, вычислять по ним. Он ничего не знает про order_items; он видит только столбцы подзапроса под теми именами, которые дал им подзапрос. Поэтому у каждого вычисляемого столбца подзапроса должен быть псевдоним.
После закрывающей скобки идёт имя таблицы, здесь — AS totals. SQLite его не требует, а большинство других баз данных требуют, и оно нужно всякий раз, когда вы обращаетесь к столбцам подзапроса, например в соединении. Да, подзапрос можно соединять и с другими таблицами. Вот три самых больших заказа с датами из orders:
SELECT o.id, o.ordered_at, t.total
FROM (
SELECT order_id, SUM(quantity * price) AS total
FROM order_items
GROUP BY order_id
) AS t
JOIN orders AS o ON o.id = t.order_id
ORDER BY t.total DESC, o.id
LIMIT 3;| id | ordered_at | total |
|---|---|---|
| 11 | 2024-09-30 | 85 |
| 14 | 2024-12-20 | 75 |
| 5 | 2024-04-02 | 65 |
Типичная ошибка: использовать столбец, которого подзапрос не возвращает. Внешний запрос видит только order_id и total, поэтому price или quantity в нём заканчиваются ошибкой no such column.
Задание
- 1
Сколько клиентов сделали по одному заказу, сколько по два и так далее? В подзапросе посчитайте заказы каждого клиента в
ordersкакorder_count. Во внешнем запросе сгруппируйте его строки поorder_countи посчитайте их какcustomer_count. (Клиенты, ничего не заказывавшие, вordersотсутствуют, поэтому не учитываются.) Отсортируйте поorder_count:order_count customer_count 1 1 2 6 3 3 4 2 - 2
Ниже покажите игры, которые стоят дороже средней цены своего жанра: название, жанр, цену и среднюю цену жанра, округлённую до одного знака после запятой, как
genre_average. Вычислите среднюю цену каждого жанра в подзапросе и соедините его сgamesпо жанру. Отсортируйте по жанру, затем по названию:title genre price genre_average Robot Rebellion Action 40 32.5 Star Pilots Action 35 32.5 Mystery Manor Adventure 25 20.0 … … … …