Условие
Какие из утверждений об агрегатных функциях в SELECT-запросе верны?
- (а) можно использовать без
GROUP BY - (б) их нельзя использовать в
WHERE - (в) их нельзя использовать в
HAVING - (г) их нельзя использовать в
SELECT
Решение
Верны (а) и (б).
(а) Без GROUP BY — да, можно
Агрегат без GROUP BY работает как «вся таблица — одна группа»:
SELECT COUNT(*), AVG(salary), MAX(salary)
FROM employees;
-- одна строка с тремя числамиБез GROUP BY нельзя смешивать агрегат и не-агрегат:
-- ошибка: department не агрегат и не в GROUP BY
SELECT department, COUNT(*)
FROM employees;(б) В WHERE — нельзя
WHERE выполняется до агрегации (см. порядок выполнения). Поэтому агрегат там не вычислен и недоступен.
-- ошибка
SELECT * FROM employees WHERE COUNT(*) > 5;Обходной путь — подзапрос или window function:
SELECT * FROM (
SELECT *, COUNT(*) OVER () AS cnt FROM employees
) t WHERE cnt > 5;(в) В HAVING — наоборот, можно и нужно
SELECT department, COUNT(*)
FROM employees
GROUP BY department
HAVING COUNT(*) > 3;(г) В SELECT — можно
Это очевидно: SELECT COUNT(*) FROM t; — самый частый запрос.
Можно ли в ORDER BY
Да, в ORDER BY агрегат разрешён:
SELECT department, COUNT(*) AS cnt
FROM employees
GROUP BY department
ORDER BY COUNT(*) DESC;Window functions — отдельная история
COUNT(*) OVER (PARTITION BY ...) — это окно, не агрегат в обычном смысле. Можно использовать в SELECT и ORDER BY, но нельзя в WHERE (и в HAVING тоже, потому что окно вычисляется после).
Подводные камни
SELECT name, COUNT(*) FROM tбез GROUP BY — синтаксическая ошибка в строгом режиме. MySQL до 5.7 разрешал, выдавая случайное значениеname.COUNT(*)пустой таблицы = 0, ноSUM/AVGвернутNULL. Заворачивайте вCOALESCE, если нужна 0.HAVINGбезGROUP BY— валиден; работает над всем результатом как над одной группой.
Эталонный ответ
Верны утверждения (а) и (б): агрегат можно использовать без GROUP BY (тогда вся таблица — одна группа), но нельзя в WHERE (фильтрация по строкам происходит до агрегации).