Нарастающий итог: OVER с ORDER BY
Содержание курса
Явная ROWS-рамка и детерминированный ORDER BY: построчное накопление без неожиданностей
Чтобы сумма росла строго по одной строке, нужно переключиться на физический счёт строк, а не логическое объединение по значению ключа. Для этого рамка записывается явно:
SUM(amount) OVER (
ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
ROWS считает строки как физические объекты: в рамку входит всё от первой строки раздела до текущей включительно, независимо от того, совпадают ли их даты. Скачка больше нет — каждая строка добавляет ровно своё значение.
Но здесь появляется другая проблема. Если ORDER BY задан только по дате, а две строки имеют одинаковую дату, СУБД вправе выдать их в любом порядке. При одном запуске строка с amount = 100 окажется первой, при другом — строка с amount = 200. Нарастающий итог будет разным, хотя запрос не менялся.
Решение — добавить уникальный столбец вторым ключом сортировки:
SUM(amount) OVER (
ORDER BY sale_date, sale_id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
Теперь полный ключ сортировки уникален для каждой строки, и порядок воспроизводим при каждом запуске.
Важный нюанс: если добавить уникальный sale_id в ORDER BY, то и неявный RANGE перестанет давать скачки — потому что полные ключи теперь различаются, и ни одна пара строк уже не попадает в одну «RANGE-группу». То есть при уникальном ORDER BY разница между RANGE и ROWS исчезает численно. Тем не менее явная ROWS-рамка остаётся предпочтительной: она точно описывает намерение (построчное накопление), не полагается на неявные правила и читается без знания деталей RANGE-семантики.
Коротко о разнице: RANGE объединяет строки по равенству значения ключа — это логическая группировка. ROWS считает строки физически — каждая строка отдельна, вне зависимости от значений. Для нарастающего итога нужен ROWS плюс уникальный ORDER BY.
