Оператор HAVING

Мы уже рассматривали запрос получения средней стоимости аренды жилых помещений в зависимости от типа жилья:

MySQL
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
home_typeavg_price
Private room89.4286
Entire home/apt148.6667
Shared room40

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

Обладая предыдущим опытом, есть большой соблазн попытаться использовать для этих целей оператор WHERE. Но при попытке выполнить такой запрос СУБД неминуемо выдаст ошибку, указав, что мы некорректно используем синтаксис WHERE avg_price > 50.

MySQL
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
WHERE avg_price > 50

Говоря наперёд, для фильтрации групп мы должны использовать оператор HAVING:

MySQL
SELECT home_type, AVG(price) as avg_price FROM Rooms
GROUP BY home_type
HAVING avg_price > 50
home_typeavg_price
Private room89.4286
Entire home/apt148.6667

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

Но почему же мы не могли использовать WHERE, и зачем нужен отдельный оператор для этой цели? Все дело в порядке выполнения SQL запроса.

Схема порядка выполнения SQL запроса

Наш первый запрос был неверный, потому что мы пытались использовать поле avg_price у образовавшихся групп ещё до их образования, так как выполнение оператора WHERE предшествует группировке.

То есть оператор WHERE в момент его исполнения ничего не знает о последующей группировке, он работает только с записями из таблицы. Так мы, например, с его помощью можем отфильтровать записи таблицы Rooms по цене до применения группировки и лишь затем вычислить среднюю стоимость групп оставшегося жилья:

MySQL
SELECT home_type, AVG(price) as avg_price FROM Rooms
WHERE price > 50
GROUP BY home_type
home_typeavg_price
Private room96.875
Entire home/apt148.6667

Общая структура запроса с оператором HAVING

MySQL
SELECT [константы, агрегатные_функции, поля_группировки]
FROM имя_таблицы
WHERE условия_на_ограничения_строк
GROUP BY поля_группировки
HAVING условие_на_ограничение_строк_после_группировки
ORDER BY условие_сортировки

Пример использования HAVING

Для примера давайте получим минимальную стоимость каждого типа жилья c телевизором. При этом нас интересуют только типы жилья, содержащие как минимум 5 жилых помещений, относящихся к ним.

Чтобы получить такой результат, мы должны:

  • Сначала получить все данные из таблицы

    MySQL
    SELECT ... FROM Rooms;
    
  • Затем выбрать из всех записей таблицы Room только интересующие нас, т.е. только жильё с телевизором

    MySQL
    SELECT ... FROM Rooms
    WHERE has_tv = True
    
  • Затем сгруппировать данные записи о жилых помещениях по их типу

    MySQL
    SELECT ... FROM Rooms
    WHERE has_tv = True
    GROUP BY home_type
    
  • После этого отфильтровать полученные группы по условию. Нас интересуют группы, имеющие как минимум 5 представителей

    MySQL
    SELECT ... FROM Rooms
    WHERE has_tv = True
    GROUP BY home_type
    HAVING COUNT(*) >= 5
    
  • И под конец посмотреть, что нас просят в задании и, соответственно, добавить вывод необходимой информации. В нашем случае, нам необходимо вывести название типа жилья и его минимальную стоимость.

    MySQL
    SELECT home_type, MIN(price) as min_price FROM Rooms
    WHERE has_tv = True
    GROUP BY home_type
    HAVING COUNT(*) >= 5;