Чем отличается оконная функция от агрегатной? Пример.

Оконная функция (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).

  • Нужно анализировать данные построчно, с доступом к другим строкам (например, сравнение с предыдущей/следующей).

  • Требуется комбинировать агрегаты и строки — отчёты, дашборды, ранжирование, выделение максимумов в группе.

Когда использовать агрегатные функции

  • Нужны сводные данные — отчёты по категориям, суммарные значения.

  • Нужно группировать строки, чтобы уменьшить количество строк в выборке.

  • Используется для дешевых аналитических операций, когда нет необходимости видеть отдельные строки.

Таким образом, агрегатные функции — это инструмент сведения данных, а оконные — инструмент анализа в контексте данных, с сохранением строк.