Чем отличается оконная функция от агрегатной? Пример.
Оконная функция (window function) и агрегатная функция (aggregate function) — это инструменты в SQL для работы с множеством строк, но применяются они по-разному и дают разные результаты.
Основное отличие
Характеристика | Агрегатная функция | Оконная функция |
---|---|---|
Возвращает | Одну строку на группу | Столько строк, сколько в исходных данных |
--- | --- | --- |
Применение | Группировка и сведение данных | Анализ в пределах "окна", без сведения |
--- | --- | --- |
Видна вся группа? | Нет — строки агрегируются в одну | Да — каждая строка остаётся видимой |
--- | --- | --- |
Примеры функций | SUM, AVG, COUNT, MAX, MIN | Те же + ROW_NUMBER(), RANK(), LEAD(), LAG() |
--- | --- | --- |
Ключевые слова | GROUP BY | OVER (PARTITION BY ... ORDER BY ...) |
--- | --- | --- |
Удаляет строки? | Да, группирует их | Нет, каждая строка остаётся в результате |
--- | --- | --- |
Агрегатные функции: пример
Допустим, есть таблица sales:
id | employee | region | amount
-------------------------------
1 | Alice | East | 100
2 | Bob | West | 200
3 | Alice | East | 300
4 | Bob | West | 150
Если хотим узнать суммарные продажи по сотрудникам:
SELECT employee, SUM(amount) AS total_sales
FROM sales
GROUP BY employee;
Результат:
employee | total_sales
-----------------------
Alice | 400
Bob | 350
Мы видим по одной строке на сотрудника — это поведение агрегатной функции.
Оконные функции: пример
Теперь, допустим, нам нужно показать все продажи, но рядом с каждой строкой — общую сумму продаж этого сотрудника. То есть хотим видеть строки без группировки, но с агрегированной информацией.
SELECT
id,
employee,
amount,
SUM(amount) OVER (PARTITION BY employee) AS total_sales
FROM sales;
Результат:
id | employee | amount | total_sales
------------------------------------
1 | Alice | 100 | 400
3 | Alice | 300 | 400
2 | Bob | 200 | 350
4 | Bob | 150 | 350
Как видно, каждая строка остаётся, но теперь в ней добавлена информация о суммарных продажах сотрудника — это и есть поведение оконной функции.
Другой пример: ROW_NUMBER() — типичная оконная функция
Пусть мы хотим нумерацию продаж по каждому сотруднику:
SELECT
id,
employee,
amount,
ROW_NUMBER() OVER (PARTITION BY employee ORDER BY amount DESC) AS row_num
FROM sales;
Результат:
id | employee | amount | row_num
-------------------------------
3 | Alice | 300 | 1
1 | Alice | 100 | 2
2 | Bob | 200 | 1
4 | Bob | 150 | 2
Здесь используется окно: мы разбиваем (PARTITION BY) по employee, сортируем внутри employee по amount DESC, и назначаем номер строки.
Сравнение на реальной задаче
Задача: Показать все продажи по регионам, но рядом показать:
-
максимальную сумму продажи в этом регионе,
-
номер продажи по дате.
SELECT
id,
employee,
region,
amount,
MAX(amount) OVER (PARTITION BY region) AS max_in_region,
ROW_NUMBER() OVER (PARTITION BY region ORDER BY id) AS sale_order
FROM sales;
Оконные функции дают возможность совмещать:
-
агрегаты (MAX) с сохранением строк,
-
аналитику (ROW_NUMBER),
-
скользящие вычисления (LAG, LEAD, AVG(...) OVER ROWS BETWEEN и т.д.).
Когда использовать оконные функции
-
Нужен контекст группы, но строки не должны исчезать (в отличие от GROUP BY).
-
Нужно анализировать данные построчно, с доступом к другим строкам (например, сравнение с предыдущей/следующей).
-
Требуется комбинировать агрегаты и строки — отчёты, дашборды, ранжирование, выделение максимумов в группе.
Когда использовать агрегатные функции
-
Нужны сводные данные — отчёты по категориям, суммарные значения.
-
Нужно группировать строки, чтобы уменьшить количество строк в выборке.
-
Используется для дешевых аналитических операций, когда нет необходимости видеть отдельные строки.
Таким образом, агрегатные функции — это инструмент сведения данных, а оконные — инструмент анализа в контексте данных, с сохранением строк.