В чём разница между агрегирующей и оконной функцией в SQL?

Ответ

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

Агрегирующая функция (GROUP BY)

  • Применяется к группам строк, определённым предложением GROUP BY.
  • Результат: Каждая группа строк сворачивается в одну итоговую строку. Исходное количество строк в выводе сокращается.
  • Пример: Подсчёт суммы продаж по каждому отделу.
    SELECT department_id, SUM(sale_amount) AS total_sales
    FROM sales
    GROUP BY department_id;
    -- В результате будет по одной строке на каждый department_id.

Оконная функция (OVER)

  • Применяется к набору строк, связанных с текущей строкой ("окну"), определяемому предложением OVER().
  • Результат: Вычисление производится для каждой строки отдельно, не сокращая общее количество строк в результате. К исходным данным добавляется новый столбец.
  • Пример: Добавление к каждой строке продажи информации о средней цене в её отделе.
    SELECT employee_id, sale_amount, department_id,
       AVG(sale_amount) OVER (PARTITION BY department_id) AS avg_department_sale
    FROM sales;
    -- В результате будет столько же строк, сколько в таблице sales, но с новым столбцом avg_department_sale.
Ключевое отличие наглядно: Подход Сворачивает строки? Синтаксис Пример результата для 10 строк в 2-х отделах
Агрегация Да GROUP BY 2 строки (по одной на отдел)
Оконная функция Нет OVER(...) 10 строк (все исходные), но с новым вычисленным столбцом

Практическое применение оконных функций: ROW_NUMBER(), RANK(), LAG()/LEAD() для анализа временных рядов, вычисления скользящего среднего.

Ответ 18+ 🔞

Слушай, вот реально объясняю, как будто на пальцах. Представь, что у тебя есть таблица с продажами, и ты хочешь посчитать, сколько каждый отдел наторговал.

Агрегатная функция с GROUP BY — это как если бы ты взял всех сотрудников отдела, запихнул их в один мешок, хорошенько потряс, и на выходе получил одну бумажку с итоговой суммой по всему отделу. Всех в кучу, одну цифру. Исходные строки — они как бы схлопнулись, пропали. Осталась только сводка.

SELECT department_id, SUM(sale_amount) AS total_sales
FROM sales
GROUP BY department_id;
-- Тут ты получаешь, условно, 5 строк, если у тебя 5 отделов. Всё, ебушки-воробушки, детализацию по каждому менеджеру потерял.

А теперь оконная функция — это вообще хитрая жопа. Она работает по-другому. Она не сворачивает нихуя. Она смотрит на каждую строчку в отдельности, но при этом оглядывается вокруг — в своё «окно». И для каждой исходной строки выдаёт свой расчёт, но с учётом соседей.

SELECT employee_id, sale_amount, department_id,
       AVG(sale_amount) OVER (PARTITION BY department_id) AS avg_department_sale
FROM sales;
-- Вот тут магия! Ты получишь ВСЕ строки обратно. Всех менеджеров. Но к данным каждого прилепится средняя цена по его отделу. То есть ты видишь и частное, и общее сразу. Удобно, ёпта!

Короче, главная разница — в результате:

  • GROUP BY: Берешь кучу строк, делаешь из них одну. Сворачиваешь. Исходные данные схлопнулись, как шагреневая кожа. Осталась только сводка по группам. Терпения ноль ебать, когда пытаешься разобраться.
  • OVER(): Берешь каждую строку, смотришь на её окружение, приклеиваешь к ней результат и идешь дальше. НЕ сворачиваешь. Все исходные строки на месте, живые, целые, просто с новым крутым столбцом.

Наглядная хуйня:

Что делаем? Схлопываем строки? Синтаксис Что на выходе? (10 строк, 2 отдела)
Агрегация (GROUP BY) Да, блядь! GROUP BY 2 строки. По одной на отдел. Всё, конец.
Оконная функция (OVER) Нет, ни хуя! OVER(...) 10 строк. Все как были. Но у каждой теперь есть, например, avg_department_sale.

Где это реально пригождается, спросишь? Да везде! Ну, например, ROW_NUMBER() чтобы пронумеровать заказы внутри клиента, RANK() чтобы понять, кто в топе по продажам, LAG() чтобы посмотреть, а сколько этот же клиент покупал в прошлый раз. Мощнейший инструмент, просто овердохуища возможностей. Главное — понять эту разницу: схлопнул или приклеил. Всё остальное — дело техники.