В аналитическом запросе оконная функция указана после GROUP BY: над какими строками она фактически работает — исходными или уже сгруппированными?
Оконная функция работает уже с результатом группировки, то есть с теми строками, которые остались после применения GROUP BY и агрегатов. Она не видит исходные строки таблицы, если они были свернуты агрегированием.
Например, после группировки по отделу оконная функция получает по одной строке на отдел и может вычислять итоги, доли или ранги между отделами.
Обычный GROUP BY решает задачу свёртки множества исходных строк в более компактный результат, но при этом удаляет детализацию. Оконные функции появились как способ выполнять аналитические вычисления по связанному набору строк, сохраняя строки результата.
Совместное использование этих механизмов позволяет сначала получить агрегаты нужного уровня, а затем анализировать уже агрегированные строки: сравнивать группы, вычислять их доли и ранжировать их.
Важно различать исходные строки и строки промежуточного результата. Если продажи сгруппированы по отделам, оконная функция, расположенная в том же запросе, не сможет отдельно обработать каждую продажу: в её входном наборе останется только одна строка на отдел.
Ошибка в понимании уровня данных приводит к неверным отчётам. Например, попытка вычислить долю отдела от общего числа продаж может случайно превратиться в долю отдела от общей суммы уже агрегированных отделов — это корректно только при соответствующем выборе агрегата и знаменателя.
Логически запрос обрабатывается примерно в следующем порядке: FROM и JOIN формируют исходный набор, WHERE отбрасывает строки, GROUP BY и агрегаты формируют группы, HAVING фильтрует группы, затем оконные функции вычисляются по строкам полученного набора, а ORDER BY задаёт порядок итогового вывода.
Поэтому оконная функция после GROUP BY видит агрегированные значения. Например, конструкция с вложенным агрегатом сначала считает сумму внутри каждого отдела, а затем оконная функция складывает суммы отделов:
Внутренний SUM(amount) выполняется на уровне каждой группы. Внешний SUM(...) OVER () применяется уже к результатам этих групп и не требует нового GROUP BY, потому что оконная функция не сокращает число строк.
Если оконный расчёт должен работать по исходным продажам, его обычно выполняют до отдельной агрегации — например, во внутреннем запросе или Common Table Expression. Если же нужен анализ групп, удобнее сначала агрегировать данные, а затем применить окно к агрегированному набору.
Следует учитывать, что конкретные допустимые формы вложения агрегатов и оконных функций могут немного различаться между СУБД. Надёжный и читаемый вариант — явно разделять этапы с помощью подзапроса или CTE, когда выражение становится сложным.
Нужно построить отчёт по регионам: показать выручку каждого региона, его долю в общей выручке и место в рейтинге. Вариант с оконными функциями непосредственно над таблицей продаж неудобен: одна продажа становится одной строкой отчёта, а региональная выручка повторяется на каждой строке.
Можно сначала посчитать выручку по регионам, а затем применить оконные функции к полученным строкам. Это делает уровень данных явным, исключает повторный подсчёт и позволяет корректно ранжировать именно регионы.
Альтернатива — несколько независимых агрегирующих подзапросов. Она может быть понятнее в простом случае, но часто приводит к повторному чтению данных и более сложному сопровождению. Выбранный подход с одной агрегацией и окнами обычно компактнее и лучше отражает последовательность расчёта.
Да. HAVING удаляет группы до вычисления оконной функции, поэтому окно видит только те сгруппированные строки, которые прошли условие HAVING. Общий итог или ранг после этого будет рассчитан по оставшимся группам, а не по всем группам до фильтрации.
Оконная функция вычисляет значение для каждой строки входного набора и не схлопывает этот набор. Поэтому общий итог будет повторён в каждой строке результата. Сокращение количества строк выполняют GROUP BY или DISTINCT, а не оконная функция.
Отдельной продажи в результате уже нет, поэтому такое выражение не соответствует уровню данных. Доступны только выбранные групповые столбцы и агрегаты, а оконная функция может ранжировать, например, по сумме отдела. Для ранжирования отдельных продаж сначала нужно сохранить уровень продаж, а группировку выполнить на другом этапе.