JavaRush /Курсы /SQL SELF /Синтаксис OVER() и его ключевые особенности...

Синтаксис OVER() и его ключевые особенности

SQL SELF
29 уровень , 2 лекция
Открыта

OVER() — это инструкция, которая говорит SQL, над каким набором строк нужно применить оконную функцию. Можно сказать, это способ, который определяет "окно" данных для применения оконной функции. Представьте, что у нас есть комната, полная людей, и мы хотим подсчитать, сколько людей стоят на каждом квадратном метре пола. OVER() укажет, в какой именно части комнаты мы сосредоточим свои усилия. Другими словами, он задаёт, над каким набором строк будет работать функция.

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

Синтаксис:

оконная_функция() OVER (
    [PARTITION BY ...]
    [ORDER BY ...]
    [ROWS/RANGE ...]
)

Где:

  • PARTITION BY — разбивает набор данных на логические группы
  • ORDER BY — задает порядок строк внутри каждой группы
  • ROWS/RANGE — уточняет размер "окна" (например, текущая строка + 1 следующая)

Пример: OVER() без параметров

Когда OVER() используется без дополнительных параметров, это означает, что функция, указанная перед ним, будет работать по всему набору данных.

SELECT
    employee_id,
    salary,
    ROW_NUMBER() OVER () AS row_num -- ROW_NUMBER() будет применена ко всем строкам результата
FROM employees;

Что происходит?

  1. ROW_NUMBER() назначает уникальный номер каждой строке.
  2. Поскольку в OVER() не указано никаких параметров, все строки из таблицы employees обрабатываются как единое целое.

Результат:

employee_id salary row_num
1 50000 1
2 60000 2
3 55000 3

Использование PARTITION BY для задания групп

Отлично, теперь представьте, что нас интересует нумерация сотрудников не по всей компании, а внутри каждого отдела. Здесь на арену выходит PARTITION BY.

PARTITION BY внутри OVER() разбивает данные на группы (или "разделы"). Для каждой группы функция вычисляет значение отдельно. То есть, если бы ROW_NUMBER() был официантом, он бы начинал нумерацию заново для каждого "стола" (раздела).

Пример: используем PARTITION BY

SELECT
    department_id,
    employee_id,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department_id) AS row_num
FROM employees;

Что происходит?

  1. Данные из таблицы employees разделены на группы по значению department_id.
  2. В каждой группе строкам назначается порядковый номер через ROW_NUMBER().

Результат:

department_id employee_id salary row_num
1 1 50000 1
1 3 55000 2
2 2 60000 1

Использование ORDER BY для задания порядка

Теперь давайте добавим немного структуры. Представьте, что нам нужно не просто нумеровать строки, а делать это в определённом порядке, например, начиная с самой высокой зарплаты. Эта задача решается с помощью ORDER BY.

ORDER BY определяет порядок, в котором строки будут обрабатываться оконной функцией.

Пример: используем ORDER BY внутри OVER()

SELECT
    department_id,
    employee_id,
    salary,
    RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank
FROM employees;

Что происходит?

  1. Данные разделяются на группы (PARTITION BY department_id).
  2. Внутри каждой группы строки сортируются по убыванию зарплаты (ORDER BY salary DESC).
  3. Каждой строке присваивается ранг с учётом сортировки.

Результат:

department_id employee_id salary rank
1 3 55000 1
1 1 50000 2
2 2 60000 1

Комбинирование оконных функций

SQL позволяет использовать несколько оконных функций в одном запросе, причём каждая из них может работать по своему уникальному набору правил. Это всё равно что в одной комнате одновременно играет музыка и ведётся подсчёт людей — каждый процесс независим!

Пример: несколько оконных функций

SELECT
    department_id,
    employee_id,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS row_num,
    AVG(salary) OVER (PARTITION BY department_id) AS avg_salary
FROM employees;

Что происходит?

  1. ROW_NUMBER() нумерует строки в каждой группе по убыванию зарплаты.
  2. AVG() вычисляет среднюю зарплату в каждой группе.

Результат:

department_id employee_id salary row_num avg_salary
1 3 55000 1 52500
1 1 50000 2 52500
2 2 60000 1 60000

Примеры из реальной жизни

Оконные функции с OVER() используются во множестве реальных сценариев. Вот лишь несколько примеров:

  • Аналитика продаж: ранжирование товаров по количеству продаж в каждой категории.
  • Рейтинги: определение позиций студентов в каждой группе по среднему баллу.
  • Временные ряды: накопительная сумма продаж в разрезе времени.

Пример из аналитики продаж:

SELECT
    category_id,
    product_id,
    product_name,
    SUM(sales) OVER (PARTITION BY category_id ORDER BY sales DESC) AS cumulative_sales
FROM products;

Распространённые ошибки при работе с оконными функциями

  1. Отсутствие PARTITION BY

Если вы не используете PARTITION BY, оконная функция применяется ко всей таблице. Это может привести к неожиданным результатам, особенно если вы ожидали разбивку по группам.

💡 Убедитесь, что вы явно указали, как именно должна делиться таблица — например, по пользователю, заказу или категории.


  1. Некорректные типы данных в ORDER BY

ORDER BY внутри оконной функции чувствителен к типам данных. Если вы сортируете по полю с датой, сохранённой как текст (VARCHAR), порядок может оказаться алфавитным, а не хронологическим.

💡 Преобразуйте такие поля в нужный тип (DATE, INTEGER и т.д.) до сортировки.

  1. Неправильное использование ROWS BETWEEN

По умолчанию оконные функции работают с рамками, определяемыми ROWS BETWEEN. Если вы явно не укажете рамку, может применяться поведение RANGE, которое ведёт себя по-другому и может возвращать больше строк, чем вы ожидали.

💡 Для точного контроля используйте ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, если нужен накопительный итог от начала до текущей строки.

  1. Неправильная работа с NULL

Оконные функции могут по-разному обрабатывать NULL. Например, RANK() и DENSE_RANK() будут считать NULL как значение и присвоят ему отдельный ранг.

💡 Используйте NULLS LAST или NULLS FIRST в ORDER BY, если важно, где должны находиться NULL.

  1. Применение агрегатных оконных функций вместо обычных

Иногда используют оконные агрегатные функции (SUM() OVER(...)) там, где достаточно обычных агрегатов с GROUP BY, что усложняет запрос и замедляет выполнение.

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

2
Задача
SQL SELF, 29 уровень, 2 лекция
Недоступна
Нумерация строк в таблице
Нумерация строк в таблице
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Ra Уровень 35 Student
5 августа 2025
Полный синтаксис с примерами значений:

sql
function_name(expression) OVER (
    [PARTITION BY col1, col2]
    [ORDER BY col3 [ASC|DESC], col4 [NULLS FIRST|LAST]]
    [
        ROWS BETWEEN 3 PRECEDING AND CURRENT ROW |
        RANGE BETWEEN INTERVAL '1 day' PRECEDING AND CURRENT ROW |
        GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING
    ]
    [EXCLUDE CURRENT ROW | EXCLUDE GROUP | EXCLUDE TIES | EXCLUDE NO OTHERS]
)
P.S. ещё полнее тут, в сочетании с SELECT https://www.stratascratch.com/blog/the-ultimate-guide-to-sql-window-functions/