HAVING
Так же, как и предложение WHERE
ограничивает строки в наборе данных, теми которые удовлетворяют условию поиска, с той разницей, что предложение HAVING
накладывает ограничения на агрегированные строки сгруппированного набора.Предложение HAVING
не является обязательным и может быть использовано только в сочетании с предложением GROUP BY
.
Условие(я) в предложении HAVING
может ссылаться на:
-
Любой агрегированный столбец в списке выбора
SELECT
. Это наиболее широко используемый случай; -
Любое агрегированное выражение, которое не находится в списке выбора
SELECT
, но разрешено в контексте запроса. Иногда это полезно; -
Любой столбец в списке
GROUP BY
. Однако более эффективно фильтровать не агрегированные данные на более ранней стадии в предложенииWHERE
; -
Любое выражение, значение которого не зависит от содержимого набора данных (например, константа или контекстная переменная). Это допустимо, но совершенно бессмысленно, потому что такое условие, не имеющее никакого отношения к самому набору данных, либо подавит весь набор, либо оставит его не тронутым.
Предложение HAVING
не может содержать:
-
Не агрегированные выражения столбца, которые не находятся в списке GROUP BY;
-
Позицию столбца. Целое число в предложении
HAVING
– просто целое число; -
Псевдонимы столбца –- даже если они появляются в предложении
GROUP BY
.
Примеры
Перестроим наши ранние примеры.Мы можем использовать предложение HAVING
для исключения малых групп студентов:
SELECT
class,
COUNT(*) AS num_boys,
AVG(age) AS boys_avg_age
FROM students
WHERE sex = 'M'
GROUP BY class
HAVING COUNT(*) >= 5
Выберем только группы, которые имеют минимальный разброс по возрасту 1.2 года:
SELECT
class,
COUNT(*) AS num_boys,
AVG(age) AS boys_avg_age
FROM students
WHERE sex = 'M'
GROUP BY class
HAVING MAX(age) - MIN(age) > 1.2
Обратите внимание, что если вас действительно интересует эта информация, то неплохо бы включить в список выбора min(age)
и max(age)
или выражение max(age) – min(age)
.
Следующий запрос отбирает только учеников 3 класса:
SELECT
class,
COUNT(*) AS num_boys,
AVG(age) AS boys_avg_age
FROM students
WHERE sex = 'M'
GROUP BY class
HAVING class STARTING WITH '3'
Однако гораздо лучше переместить это условие в предложение WHERE
:
SELECT
class,
COUNT(*) AS num_boys,
AVG(age) AS boys_avg_age
FROM students
WHERE sex = 'M' AND class STARTING WITH '3'
GROUP BY class