Порядок частей запроса
Теперь вы знаете все части запроса. Писать их нужно в таком порядке, и любую из них, кроме SELECT, можно опустить:
SELECT …
FROM …
WHERE …
GROUP BY …
HAVING …
ORDER BY …
LIMIT …;Однако база данных выполняет их не в том порядке, в котором вы их пишете, а в том, в котором они ей нужны:
FROM— берёт строки таблицы.WHERE— оставляет строки, удовлетворяющие его условию.GROUP BY— раскладывает строки по группам, а агрегатные функции вычисляют свои значения для каждой группы.HAVING— оставляет группы, удовлетворяющие его условию.SELECT— вычисляет столбцы результата и называет их с помощьюAS(аDISTINCTубирает повторяющиеся строки).ORDER BY— сортирует строки результата.LIMIT— оставляет только первые строки (пропустивOFFSETстрок).
Этот порядок объясняет многое из того, что вы видели в этом уроке. WHERE выполняется до GROUP BY, поэтому не может использовать агрегатные функции: групп ещё нет. HAVING выполняется после GROUP BY, поэтому может. А ORDER BY выполняется после SELECT, поэтому уже знает имена, которые вы дали столбцам: вот почему работает ORDER BY game_count DESC.
По той же логике WHERE, GROUP BY и HAVING не могут использовать псевдонимы, потому что выполняются до того, как SELECT их создал. В большинстве баз данных, таких как PostgreSQL, MySQL, SQL Server или Oracle, псевдоним в WHERE — это ошибка, а некоторые не разрешают его и в GROUP BY или HAVING. SQLite снисходителен: найдя имя, которое не является столбцом таблицы, он ищет среди псевдонимов, поэтому в SQLite это работает, даже в WHERE:
SELECT title, price * 2 AS two_copies
FROM games
WHERE two_copies > 100;| title | two_copies |
|---|---|
| Knight's Oath | 120 |
Но не рассчитывайте на это. Псевдоним с именем настоящего столбца означает этот столбец; псевдоним агрегатной функции нельзя использовать в WHERE даже в SQLite, потому что групп ещё нет; а в другой базе данных такой запрос перестанет работать. В WHERE, GROUP BY и HAVING пишите само выражение (WHERE price * 2 > 100, HAVING COUNT(*) >= 3), а псевдонимы используйте в ORDER BY.
Во втором запросе этого упражнения вы наконец исключите возвращённые заказы. Был ли заказ возвращён, записано в orders, а позиции находятся в order_items, и чтобы использовать обе таблицы в одном запросе, их нужно соединить. Вы узнаете, как это делается, в уроке о соединениях, который идёт после небольшого мини-проекта по пройденному материалу. До тех пор можно использовать ID возвращённых заказов: SELECT id FROM orders WHERE status = 'refunded'; показывает, что это 7 и 18, а WHERE order_id NOT IN (7, 18) затем исключает их позиции. Но это временная мера: список ID, написанный вручную, устареет, как только вернут ещё один заказ, а запрос с соединением находит возвращённые заказы сам.
Задание
- 1
Коллега написал запрос, который должен показывать клиентов, сделавших в 2025 году не меньше 2 заказов, но он завершается ошибкой. Исправьте его, чтобы получилось вот это:
customer_id orders_2025 3 2 11 2 13 2 - 2
Ниже напишите запрос, в котором есть все части. Какие игры заработали больше всего в заказах, которые не были возвращены? Из
order_itemsисключите позиции возвращённых заказов 7 и 18 (с помощьюNOT IN, как объяснено выше), сгруппируйте строки по играм и покажитеgame_id, количество проданных экземпляров (суммуquantity) в столбцеcopiesи суммуquantity * priceв столбцеrevenue. Оставьте только игры, которых продано не меньше 3 экземпляров, отсортируйте их по убыванию выручки и покажите первые 3:game_id copies revenue 15 3 180 1 4 160 14 3 90