Редът на изпълнение на заявката
Накратко: Заявката се пише от SELECT, но базата я изпълнява в ред FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY и LIMIT.
Проблем
Тук работи, там не
В урока за групите ORDER BY month ползваше псевдонима от SELECT. В урока за HAVING повтаряхме целия SUM(...), а SUM в WHERE даде грешка. Защо псевдонимът става на едно място, а на друго не?
Отговорът е в реда, в който базата чете заявката. Той не е редът, в който я пишеш.
Идеята
Пише се в един ред, изпълнява се в друг
Пишеш така:
SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT
Базата мисли така:
FROM: откъде са редовете;WHERE: кои редове остават;GROUP BY: групите;HAVING: кои групи остават;SELECT: какво се показва и как се казва;ORDER BY: подреждането;LIMIT: колко реда.
Това е логическият ред на изпълнение на заявката. Трите най-натоварени месеца, без отказаните поръчки:
Стъпка по стъпка: FROM взима 60-те поръчки. WHERE маха 7-те отказани и остават 53. GROUP BY ги разделя на 14 месеца. HAVING оставя шестте с поне 5 поръчки. SELECT смята месеца и броя и им дава имена. ORDER BY ги подрежда, а LIMIT взима първите три.
По-точно, за любопитните
Това е редът, в който заявката трябва да изглежда, че се изпълнява. Истинският план може да е друг: базата може да ползва индекс или да прескочи стъпка, стига резултатът да е същият. Плана на заявката ще видим в модула за индексите.
Идеята
Защо псевдонимът става в ORDER BY
Псевдонимът се ражда в SELECT, на стъпка 5. ORDER BY е на стъпка 6, затова името вече го има:
Трите най-големи поръчки. Това работи във всяка база. В WHERE, GROUP BY и HAVING по правило псевдонимът още го няма, защото са преди SELECT.
Пробвай
Най-активните клиенти
Покажи петимата клиенти с най-много поръчки: customer_id и броя в колона orders, най-много пръв. При равен брой по-малкият customer_id е пръв.
Решение
SELECT customer_id, COUNT(*) AS orders
FROM orders
GROUP BY customer_id
ORDER BY orders DESC, customer_id
LIMIT 5;GROUP BY customer_id, COUNT(*) AS orders, ORDER BY orders DESC, customer_id, LIMIT 5. Втората колона в ORDER BY е важна: клиенти 4, 7 и 11 имат по 4 поръчки, а цели девет клиенти имат по 3. Без нея кой ще е пети, не е обещано.
Виж го
Какво прощава SQLite
По правилото псевдоним в WHERE не би трябвало да става. Продуктите, които с 20% отстъпка струват под 1 €:
SQLite го приема. Приема псевдоним и в GROUP BY:
Другите бази не са толкова отстъпчиви. PostgreSQL приема псевдоним в GROUP BY, но не и в WHERE: там казва, че колона sale няма. SQL Server не го приема нито в WHERE, нито в GROUP BY.
Отстъпчивостта на SQLite има граници. Ако псевдонимът е същият като име на колона, WHERE взима колоната:
Излизат два продукта, а не четири: WHERE price < 1 гледа истинската цена, а не цената с отстъпка. А псевдоним на обобщение в WHERE пак е „misuse of aggregate“, защото групи на стъпка 2 още няма:
Заявка, която ще работи навсякъде: в WHERE повтаряй израза (WHERE price * 0.8 < 1), а псевдонимите ползвай свободно в ORDER BY.
Упражнение
Месечният отчет
Собственичката иска отчет за 2026 г.: за всеки месец колко поръчки има (без отказаните) и от колко различни клиенти. Месеците с по-малко от 3 поръчки са твърде тихи и не ѝ трябват.
Покажи колоните month (година-месец), orders и customers за месеците на 2026 г. с поне 3 поръчки без отказаните, по ред на месеците.
Решение
SELECT strftime('%Y-%m', ordered_at) AS month,
COUNT(*) AS orders,
COUNT(DISTINCT customer_id) AS customers
FROM orders
WHERE status <> 'cancelled' AND ordered_at >= '2026-01-01'
GROUP BY strftime('%Y-%m', ordered_at)
HAVING COUNT(*) >= 3
ORDER BY month;Всяка част е на мястото си:
WHERE status <> 'cancelled' AND ordered_at >= '2026-01-01': редовете;GROUP BY strftime('%Y-%m', ordered_at): месеците;HAVING COUNT(*) >= 3: групите;COUNT(*) AS orders, COUNT(DISTINCT customer_id) AS customers: колоните;ORDER BY month: редът.
Шест месеца. През септември 7 поръчки са от 6 клиенти: един е поръчал два пъти.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Функции за дати · Агрегатни функции: COUNT, SUM, AVG · GROUP BY: отчет по групи · HAVING: условие за групите
- Продължава в: Прозоречни функции · Пекарната, етап 3: въпросите
- Задачи по темата: Обобщаване