Открыть сервис

Оконные функции

Оконные функции (аналитические функции, window functions) — это класс функций в языке SQL, которые выполняют вычисления над набором строк, определённым оконной спецификацией (фреймом), связанным с текущей обрабатываемой строкой. В отличие от агрегатных функций (SUM, AVG, COUNT), которые группируют строки в одну результирующую, оконные функции не схлопывают строки, а возвращают для каждой строки отдельное значение, вычисленное на основе её «окна» — заданного набора соседних строк.

История и происхождение

Концепция оконных функций была впервые предложена в стандарте SQL:1999 и получила дальнейшее развитие в SQL:2003, SQL:2008 и SQL:2016. Идея возникла из необходимости выполнения аналитических расчётов (например, скользящих средних, ранжирования, накопительных итогов) без написания сложных подзапросов или использования курсоров. Коммерческие СУБД начали внедрять оконные функции постепенно: Oracle Database реализовала их в версии 8i (1999 год), Microsoft SQL Server — в 2005 году (версия 9.0), PostgreSQL — в версии 8.4 (2009 год). MySQL долгое время не поддерживал оконные функции, включив их только в версии 8.0 (2018 год). Современные системы управления базами данных, такие как ClickHouse, Snowflake, BigQuery, также поддерживают оконные функции.

Ключевые компоненты оконных функций

Оконная спецификация (OVER)

Ключевым синтаксическим элементом является предложение OVER, которое определяет окно. Оно может включать три необязательных компонента:

Если фрейм не указан явно, используется значение по умолчанию: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.

Агрегатные оконные функции

Агрегатные функции (SUM, AVG, COUNT, MIN, MAX, STDDEV и другие) могут применяться как оконные. Они вычисляют агрегат по определённому окну. Пример: ``sql SELECT id, date, amount, SUM(amount) OVER (PARTITION BY customer_id ORDER BY date) AS running_total FROM orders; `` Этот запрос вычисляет накопительный итог суммы заказов для каждого клиента, упорядоченных по дате.

Функции ранжирования

Пример: ``sql SELECT employee_id, department, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_in_dept FROM employees; ``

Аналитические функции смещения

Пример использования LAG для расчёта разницы: ``sql SELECT date, price, price - LAG(price, 1) OVER (ORDER BY date) AS price_change FROM stock_prices; ``

Функции статистического распределения

Поведение оконных функций

Примеры применения

Скользящее среднее (moving average)

``sql SELECT date, value, AVG(value) OVER (ORDER BY date ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) AS moving_avg_6 FROM sensor_data; ``

Топ-N в каждой группе

Найти двух самых высокооплачиваемых сотрудников в каждом отделе: ``sql SELECT employee_id, department, salary FROM ( SELECT *, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r FROM employees ) sub WHERE r <= 2; ``

Расчёт времени между событиями

``sql SELECT user_id, event_time, LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_event, EXTRACT(EPOCH FROM (event_time - LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time))) AS seconds_since_prev FROM events; ``

Накопительный итог с условием (проверка лимита)

Вычисление суммы заказов с остановкой при достижении лимита в 1000: ``sql SELECT id, amount, SUM(amount) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_sum, CASE WHEN SUM(amount) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) <= 1000 THEN 'inside' ELSE 'exceeded' END AS status FROM orders; ``

Особенности реализации в различных СУБД

Производительность и ограничения

Интересные факты

Источники

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →