Предложение HAVING

Если предложение WHERE определяет предикат для фильтрации строк, то предложение HAVING применяется после группировки для определения аналогичного предиката, фильтрующего группы по значениям агрегатных функций. Это предложение необходимо для проверки значений, которые получены с помощью агрегатной функции не из отдельных строк источника записей, определенного в предложении FROM, а из групп таких строк. Поэтому такая проверка не может содержаться в предложении WHERE.

Пример 5.5.5

Получить количество ПК и среднюю цену для каждой модели, средняя цена которой менее $800
SELECT model, 
       COUNT(model) AS Qty_model,
       AVG(price) AS Avg_price
FROM PC
GROUP BY model
HAVING AVG(price) < 800;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]

В результате выполнения запроса получим:

modelQty_modelAvg_price
12324425
12601350

Заметим, что в предложении HAVING нельзя использовать псевдоним (Avg_price), используемый для именования значений агрегатной функции в предложении SELECT. Дело в том, что предложение SELECT, формирующее выходной набор запроса, выполняется предпоследним перед предложением ORDER BY. Ниже приведен порядок обработки предложений в операторе SELECT:

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY

Этот порядок не соответствует синтаксическому порядку общего представления оператора SELECT, который ближе к естественному языку:

SELECT [DISTINCT | ALL]{*
| [<выражение для столбца> [[AS] <псевдоним>]] [,]}
FROM <имя таблицы> [[AS] <псевдоним>] [,]
[WHERE <предикат>]
[[GROUP BY <список столбцов>]
[HAVING <условие на агрегатные значения>] ]
[ORDER BY <список столбцов>]

Следует отметить, что предложение HAVING может использоваться и без предложения GROUP BY. При отсутствии предложения GROUP BY агрегатные функции применяются ко всему выходному набору строк запроса, т.е. в результате мы получим всего одну строку, если выходной набор не пуст.

Таким образом, если условие на агрегатные значения в предложение HAVING будет истинным, то эта строка будет выводиться, в противном случае мы не получим ни одной строки. Рассмотрим такой пример.

Пример 5.5.6

Найти максимальную, минимальную и среднюю цену на персональные компьютеры.

Решение этой задачи дает следующий запрос:

SELECT MIN(price) AS min_price,
       MAX(price) AS max_price, 
       AVG(price) avg_price
FROM PC;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]
результатам которого будет

min_pricemax_priceavg_price
350980675

Если же мы добавим в условие ограничение, скажем, на среднюю цену:

Найти максимальную, минимальную и среднюю цену на персональные компьютеры при условии, что средняя цена не превышает $600:

SELECT MIN(price) AS min_price,
       MAX(price) AS max_price, 
       AVG(price) avg_price
FROM PC
HAVING AVG(price) <= 600;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]
то в результате получим пустой результирующий набор, т.к. 675.00 > 600.

Рекомендуемые упражнения: 15, 20, 28, 37, 40, 57, 63, 67, 68, 70, 72, 76, 81, 82, 85, 87, 89, 102, 114, 126, 129