Ответ
Оконные функции (Window Functions) — это мощная функция SQL, которая позволяет выполнять вычисления над набором строк, связанных с текущей строкой запроса, без свёртки этих строк в одну, в отличие от GROUP BY. Они работают в рамках "окна", определяемого для каждой строки.
Ключевые компоненты и синтаксис:
Оконная функция определяется с помощью предложения OVER():
<функция> OVER (
[PARTITION BY <столбцы>]
[ORDER BY <столбцы>]
[ROWS/RANGE <границы окна>]
)
Практические примеры применения:
-
Агрегация без группировки (сравнение с групповой средней):
SELECT employee_id, department, salary, AVG(salary) OVER (PARTITION BY department) AS avg_dept_salary, salary - AVG(salary) OVER (PARTITION BY department) AS diff_from_avg FROM employees;Каждая строка сохраняется, но к ней добавляется средняя зарплата по её отделу.
-
Ранжирование и нумерация (например, топ-3 товара в категории):
SELECT product_id, category, sales, ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rank_in_category FROM products; -
Расчёт накопительных итогов и скользящих средних:
SELECT order_date, daily_revenue, SUM(daily_revenue) OVER (ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_revenue, AVG(daily_revenue) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS weekly_moving_avg FROM revenue_stats;
Основные типы оконных функций:
- Агрегатные:
SUM(),AVG(),COUNT(),MIN(),MAX(). - Ранжирующие:
ROW_NUMBER(),RANK(),DENSE_RANK(),NTILE(). - Функции смещения:
LAG(),LEAD()(доступ к данным из предыдущей/следующей строки). - Функции распределения:
PERCENT_RANK(),CUME_DIST().
Оконные функции незаменимы для сложной аналитической отчётности, расчёта KPI и подготовки данных, где требуется сохранить детализацию исходных строк.
Ответ 18+ 🔞
А, оконные функции в SQL! Ну это, блядь, просто песня, а не инструмент. Сидишь такой, пишешь запрос, и понимаешь, что тебе надо посчитать какую-нибудь хуйню вроде средней зарплаты по отделу, но чтобы все строки на месте остались, а не схлопнулись в одну. И тут ты вспоминаешь про OVER() — и жизнь налаживается, ёпта!
Представь: обычный GROUP BY — это как взять всех сотрудников отдела и выдать им одну общую справку: «Средняя зарплата — столько-то». А оконная функция — это подойти к каждому челу по отдельности, шепнуть ему на ушко эту цифру и сказать: «Вот, Вася, держи, сравнивай, насколько ты хуйло или молодец». И все исходные данные — они на месте, их нихуя не тронули!
Вот смотри, из чего эта магия состоит:
Всё крутится вокруг этого самого OVER(). Туда можно намешать три основных компонента, как в хороший коктейль:
<функция> OVER (
[PARTITION BY <столбцы>] <!-- Разбиваешь на куски, как торт -->
[ORDER BY <столбцы>] <!-- Сортируешь внутри этих кусков -->
[ROWS/RANGE <границы окна>] <!-- И говоришь, какие строки рядом считать -->
)
Ну и чтобы не быть голословным, вот тебе живые примеры, где эта хуйня реально спасает жопу:
-
«Сравни себя с соседом по палате» (Агрегация без схлопывания): Допустим, хочешь узнать, насколько каждый работник отстаёт или перепизживает среднюю по своему отделу.
SELECT employee_id, department, salary, AVG(salary) OVER (PARTITION BY department) AS avg_dept_salary, <!-- Вот она, магия! --> salary - AVG(salary) OVER (PARTITION BY department) AS diff_from_avg <!-- И сразу видно, лох или красавчик --> FROM employees;Каждый чувак остаётся в своей строке, но теперь у него в кармане лежит средняя температура по больнице.
-
«Кто тут у нас самый продающий?» (Ранжирование): Нужно вывести топ-3 товара в каждой категории. Без оконных функций пришлось бы городить огород из подзапросов, а тут — раз плюнуть.
SELECT product_id, category, sales, ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rank_in_category FROM products;PARTITION BY category— значит, ранжирование начнётся заново для каждой категории. И всё, пиздец, задача решена. -
«Сколько уже накопил и какая средняя за неделю?» (Накопительные итоги): Вот это вообще мощь. Хочешь видеть, как растёт выручка день за днём и какое скользящее среднее за неделю?
SELECT order_date, daily_revenue, SUM(daily_revenue) OVER (ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_revenue, AVG(daily_revenue) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS weekly_moving_avg FROM revenue_stats;ROWS BETWEEN 6 PRECEDING AND CURRENT ROW— это и есть указание «смотри на текущую строку и на шесть предыдущих». Красота, блядь!
А какие вообще бывают эти функции? Да их, блять, овердохуища!
- Агрегатные: Те же самые
SUM(),AVG(), но применяются к окну, а не ко всей таблице. - Ранжирующие:
ROW_NUMBER()(просто номер по порядку),RANK()(а вот тут могут быть одинаковые ранги и дырки),DENSE_RANK()(дырок не будет). - Функции смещения:
LAG()(загляни, что было в предыдущей строке),LEAD()(посмотри, что будет в следующей). Просто находка для анализа временных рядов, в рот меня чих-пых! - Функции распределения:
PERCENT_RANK()и прочая экзотика, но они тоже иногда нужны.
Короче, если ты делаешь аналитику, отчёты или просто хочешь не ебать мозг себе и базе кучей подзапросов — учи оконные функции. Это один из тех инструментов, после освоения которого начинаешь чувствовать себя настоящим шаманом SQL, ёпта!