Вам нужно отобрать только те группы, для которых результат агрегирования удовлетворяет условию. На каком этапе запроса должен применяться такой фильтр и почему?
Фильтр по результату агрегирования должен применяться после формирования групп и вычисления агрегата — обычно через HAVING. WHERE фильтрует отдельные строки до группировки, поэтому агрегатное условие в нём не имеет нужного контекста.
Например, сначала можно исключить отменённые заказы через WHERE, затем сгруппировать оставшиеся заказы по клиентам и оставить группы с суммой выше порога через HAVING.
В SQL понадобилось различать два уровня обработки данных: отдельные строки и получившиеся из них группы. Условие для строки нельзя автоматически применять к группе, потому что после группировки множество строк представлено одним результатом с агрегированными значениями.
Поэтому язык разделяет фильтрацию исходных строк и фильтрацию результата группировки. Это позволяет описывать аналитические запросы без предварительного ручного обхода данных.
Предположим, нужно найти клиентов, чья сумма оплаченных заказов превышает заданный порог. Если проверять сумму на уровне исходных строк, у отдельного заказа ещё нет значения общей суммы по клиенту.
Неверный выбор уровня фильтрации приводит либо к синтаксической ошибке, либо к неверному результату. Особенно опасно поместить условие в WHERE: строки будут удалены до того, как их вклад попадёт в агрегат, и итоговая сумма может измениться.
Логически запрос выполняет фильтрацию строк через WHERE, затем группирует оставшиеся строки, вычисляет агрегаты и после этого применяет HAVING к группам. Физический план оптимизатор может перестроить, но итоговая семантика должна сохраняться.
Здесь WHERE исключает неоплаченные заказы до суммирования, а HAVING исключает уже сформированные группы с недостаточной суммой. Перенос условия SUM(amount) > 100000 в WHERE невозможен: на этапе фильтрации строки такой суммы ещё не существует.
Условие, не зависящее от агрегата, обычно следует помещать в WHERE. Это уменьшает объём данных до группировки и делает намерение запроса яснее. Оптимизатор иногда сам безопасно перемещает часть условий из HAVING до группировки, но полагаться на такое преобразование как на способ изменить смысл запроса нельзя.
Нужно учитывать и состав агрегируемых строк. Например, фильтр по дате в WHERE изменит набор заказов, из которого считается сумма; тот же фильтр, применённый после агрегации, должен быть выражен иначе и может иметь другую семантику.
В отчёте по продажам требовалось показать клиентов с выручкой за текущий квартал выше 100 000 рублей, учитывая только проведённые платежи. Первый вариант помещал оба условия в HAVING: он давал правильный результат, но сначала группировал лишние строки, включая отменённые платежи и данные других периодов.
Второй вариант помещал условие по сумме в WHERE. Он был быстрее на небольшом наборе данных, но не выражал корректную логику и приводил к ошибке, поскольку сумма вычисляется только после группировки.
Выбранное решение оставило фильтры по статусу и периоду в WHERE, а условие по общей выручке — в HAVING. Такой вариант уменьшил входной набор для группировки, сохранил правильную семантику и сделал план запроса более предсказуемым.
Это зависит от диалекта и настроек SQL-системы. В переносимом запросе в HAVING следует использовать сгруппированный столбец или агрегатное выражение; обращение к неагрегированному столбцу, не определяющему группу, часто запрещается или приводит к неоднозначному результату.
Потому что WHERE удаляет строки до вычисления агрегата. Если условие ограничивает строки, оно меняет состав группы и саму сумму или количество; HAVING только решает, оставить ли уже вычисленную группу. Эквивалентность возможна лишь при доказанной независимости условия от агрегирования и его корректности для каждой исходной строки.
Если условие логически следует из значения группировочного столбца и его перенос не меняет набор строк, оптимизатор может выполнить фильтрацию раньше. Это уменьшает объём данных для группировки и ускоряет запрос. Такое преобразование является внутренней оптимизацией, а не изменением правил SQL: условия, зависящие от SUM, COUNT или другого агрегата, обычно нельзя безопасно применить к отдельным строкам.