Оконные функции позволяют выполнять вычисления по "окну" строк, не группируя их в отдельные строки, что удобно для отчетов и аналитики.
Пример:
SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS num, RANK() OVER (ORDER BY salary DESC) AS rank, DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank FROM employees;
Таблица:
| name | salary |
|---|---|
| Вася | 10000 |
| Петя | 10000 |
| Маша | 9000 |
Результат:
| name | salary | num | rank | dense_rank |
|---|---|---|---|---|
| Вася | 10000 | 1 | 1 | 1 |
| Петя | 10000 | 2 | 1 | 1 |
| Маша | 9000 | 3 | 3 | 2 |
Подводные камни:
Если не указать PARTITION BY в окне функции, как будет производиться нумерация строк в ROW_NUMBER()?
Ответ: Вся выборка данных будет считаться одной партицией. То есть нумерация будет сквозная по всем строкам, без учета каких-либо группировок.
Пример:
SELECT *, ROW_NUMBER() OVER (ORDER BY salary DESC) FROM employees; -- Все сотрудники получат уникальный номер, начиная с 1 без разбивки по отделам
История №1
В BI-отчете забыли указать PARTITION BY по отделу. Все сотрудники компании получили подряд сквозную нумерацию, а задача ставилась — идентифицировать лучших внутри каждого отдела. В результате получился некорректный TOP-N сотрудников по отделам.
История №2
Разработчик выбрал RANK() вместо ROW_NUMBER(), чтобы определить "лучшего" из группы — но при одинаковых показателях были присвоены одинаковые номера, из-за чего возникли неявные дубликаты лидеров в аналитике.
История №3
При использовании DENSE_RANK() не учли, что он запрещает пропуски в рангах, что исказило отчет о количестве "уникальных" значимых позиций при анализе продаж. Контроль на бизнес-логику выявил ошибку распределения мест.