Ответ
Обе функции выполняют вычисления над группами строк, но принципиально различаются в том, сворачивают ли они результирующий набор строк.
Агрегирующая функция (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() чтобы посмотреть, а сколько этот же клиент покупал в прошлый раз. Мощнейший инструмент, просто овердохуища возможностей. Главное — понять эту разницу: схлопнул или приклеил. Всё остальное — дело техники.