Порядок выполнения SQL-запроса

Один из самых частых вопросов: в каком порядке СУБД на самом деле выполняет части запроса.

Логический порядок выполнения — последовательность, в которой СУБД «обрабатывает» части запроса: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. Он отличается от порядка, в котором вы их пишете.

Вопрос с собеседования

«Вы пишете SELECT первым, но почему в WHERE нельзя сослаться на алиас из SELECT?» — классическая проверка понимания. Ответ: потому что WHERE вычисляется раньше, чем SELECT, и алиас в этот момент ещё не существует.

Логический порядок

Запрос вы читаете и пишете в одном порядке, а СУБД выполняет его в другом — логическом:

  1. FROMJOIN) — берём и соединяем таблицы;
  2. WHERE — фильтруем отдельные строки;
  3. GROUP BY — собираем строки в группы;
  4. HAVING — фильтруем уже группы;
  5. SELECT — вычисляем выражения и алиасы;
  6. ORDER BY — сортируем результат;
  7. LIMIT — отрезаем нужное число строк.

Из этого порядка вытекают почти все «каверзные» правила SQL. Например, в WHERE нельзя использовать агрегат COUNT(*) — группы ещё не созданы. А вот ORDER BY по алиасу из SELECT работает, потому что сортировка идёт последней.

Проверим на живом примере

Алиас total создан в SELECT. Сортировать по нему можно (ORDER BY — после SELECT), а вот фильтровать им в WHERE было бы ошибкой.

CREATE TABLE orders (
    id       INTEGER PRIMARY KEY,
    customer TEXT,
    amount   INTEGER
);

INSERT INTO orders (customer, amount) VALUES
    ('Аня',   500),
    ('Аня',   300),
    ('Борис', 900),
    ('Вера',  200);

SELECT customer, SUM(amount) AS total
FROM orders
GROUP BY customer
HAVING SUM(amount) > 400
ORDER BY total DESC;

Вывод:

Борис|900
Аня|800

Здесь видно весь конвейер: FROM взял таблицу, GROUP BY собрал заказы по клиентам, HAVING отсёк тех, у кого сумма ≤ 400, SELECT посчитал total, а ORDER BY отсортировал по этому алиасу.

Почему это важно знать

Понимание порядка — это не academическая мелочь. Оно сразу объясняет три типичные ошибки новичков: «почему алиас не виден в WHERE», «почему агрегат нельзя в WHERE» и «чем WHERE отличается от HAVING». На собеседовании ждут именно связной картины, а не заученного списка.

Итог

  • Пишем SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY, а выполняется это в порядке FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
  • Алиасы из SELECT доступны в ORDER BY, но не в WHERE и не в GROUP BY.
  • Агрегаты нельзя в WHERE — для фильтра по агрегату есть HAVING.
Проверьте себя
1. В каком порядке СУБД логически выполняет части запроса?
ASELECT → FROM → WHERE → ORDER BY
BFROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
CWHERE → FROM → SELECT → GROUP BY
DFROM → SELECT → WHERE → ORDER BY
2. Почему алиас из SELECT нельзя использовать в WHERE?
AЭто запрещено стандартом без причины
BWHERE выполняется раньше SELECT, алиас ещё не создан
CАлиасы вообще не работают в SQLite
DНужно ставить кавычки вокруг алиаса
3. Где можно сослаться на алиас, объявленный в SELECT?
AВ WHERE
BВ GROUP BY
CВ ORDER BY
DВ FROM
Поддержать проект