Рамки ROWS и RANGE
Разбирайте тонкое и часто проверяемое различие между рамками по строкам и по значениям.
«Рамки ROWS и RANGE» — бесплатный урок SQL Interview Prep на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Interview Prep содержит 4 уроков всего.
Различие, о котором спрашивают интервьюеры
Когда Вы уже умеете писать накопительный итог, естественный дополнительный вопрос звучит так: «В чём разница между ROWS и RANGE в рамке окна?» Это точный показатель знаний на среднем уровне. Многие кандидаты ежедневно используют рамки, но никогда не замечают, что эти два ключевых слова работают по-разному.
Оба варианта определяют набор строк, который видит агрегатная функция, но принцип подсчёта этого набора у них принципиально различается. Разберитесь в этом — и Вы выгодно выделитесь.
ROWS считает физические строки
ROWS работает по позициям. ROWS BETWEEN 2 PRECEDING AND CURRENT ROW буквально означает текущую строку и две физические строки непосредственно перед ней в упорядоченной последовательности.
При этом не имеет значения, совпадают ли значения ORDER BY у соседних строк. Три строки — значит три строки, без исключений. Именно такую рамку почти всегда следует использовать для скользящих средних и строгих накопительных итогов.
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS rows_sum
FROM sales;RANGE считает по значениям
RANGE работает по значениям. Он включает все строки, чьё значение ORDER BY попадает в логический диапазон относительно значения текущей строки, а не выбирает фиксированное количество строк.
Самое важное следствие: при использовании RANGE все строки с одинаковым значением ORDER BY считаются одной группой равных строк. Для всех них устанавливается одна и та же рамка, поэтому они получают один и тот же результат.
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS range_sum
FROM sales;Пример с одинаковыми значениями, показывающий разницу
Предположим, две продажи произошли 2024-03-02 и составили 30 и 40, а перед ними 2024-03-01 была продажа на 100.
- При RANGE до CURRENT ROW: обе строки за 03-02 являются равными, поэтому в обеих отображается 100 + 30 + 40 = 170.
- При ROWS до CURRENT ROW: первая строка за 03-02 показывает 130, а вторая — 170, поскольку каждая строка расширяет рамку на одну позицию.
Одни и те же данные, но разные числа. Именно это расхождение при одинаковых значениях составляет суть вопроса.
Почему по умолчанию используется RANGE
Напомним: запись OVER (ORDER BY ...) без явно заданной рамки по умолчанию означает RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
Это означает, что наивный накопительный итог незаметно использует RANGE. При уникальных ключах сортировки он совпадает с ROWS, поэтому ошибка остаётся скрытой. Как только появляются повторяющиеся значения сортировки, накопительный итог незаметно объединяет равные строки. Именно поэтому опытные инженеры явно указывают ROWS.
RANGE со смещением по числовому значению
RANGE может принимать смещение значения, а не только UNBOUNDED. RANGE BETWEEN 7 PRECEDING AND CURRENT ROW для столбца с датами или числами включает каждую строку, значение которой находится в пределах 7 единиц от текущего значения.
Для дат это даёт настоящее окно «последние 7 дней», корректно пропуская отсутствующие дни, тогда как ROWS 7 PRECEDING захватит предыдущие 7 строк независимо от пропусков. Знание этой тонкости — сильный ответ.
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
) AS last_7_days
FROM sales;ROWS игнорирует пропуски
Обратная сторона: ROWS не учитывает пропуски в данных. Если в таблице продаж отсутствуют выходные, ROWS BETWEEN 6 PRECEDING AND CURRENT ROW охватывает 7 зафиксированных дней, которые фактически могут приходиться на две календарные недели.
Поэтому выбор зависит от цели: последние N записей означают ROWS; последние N единиц значения (дней, долларов) — RANGE со смещением.
Проверка реальной поддержки диалектами
В хорошем ответе на собеседовании стоит честно отметить различия в поддержке:
- PostgreSQL поддерживает
RANGEсо смещениями (начиная с версии 11) и полностью поддерживаетROWS. - сервер SQL поддерживает
ROWSиRANGE, ноRANGE— только сUNBOUNDED/CURRENT ROW, без числовых смещений. - MySQL 8 поддерживает оба варианта, но набор типов смещения для
RANGEограничен.
Если числовое смещение RANGE недоступно, его можно воспроизвести с помощью соединения таблицы с самой собой или сгенерированного календаря. Упоминание этого показывает понимание особенностей промышленной эксплуатации.
GROUPS: третий режим
Существует малоизвестный третий режим задания рамки: GROUPS. Он считает группы равных значений, а не строки и не значения. GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW включает текущую группу равных значений и группу перед ней.
Обычно он не требуется, но его упоминание в ответ на вопрос «существуют ли другие режимы рамки?» демонстрирует глубокое понимание темы. Он поддерживается в PostgreSQL 11+ и ещё в нескольких системах.
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
) AS two_day_groups
FROM sales;Правило выбора, которое можно повторить
Сведём всю тему к одному предложению, которое можно сказать на собеседовании:
«Используйте ROWS, когда имеется в виду фиксированное количество физических строк, RANGE — когда имеется в виду логический диапазон значения, по которому выполняется сортировка, и помните, что одинаковые значения приводят к разнице: рамка по умолчанию RANGE объединяет их в одну группу».
Одного этого предложения достаточно, чтобы полностью и уверенно ответить на вопрос.
Сравнение бок о бок
Если поместить обе рамки в один запрос, различие станет наглядным. Выполните этот запрос на данных с повторяющимися датами и сравните два столбца построчно.
Для уникальных дат столбцы полностью совпадают; для одинаковых дат столбец RANGE повторяет одну и ту же сумму для равных значений, тогда как столбец ROWS увеличивается на один шаг за раз.
SELECT
sale_date,
amount,
SUM(amount) OVER (ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS rows_total,
SUM(amount) OVER (ORDER BY sale_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS range_total
FROM sales;Быстрая проверка
Две строки имеют одинаковое значение ORDER BY при рамке по умолчанию. Что произойдёт?
Итоги: ROWS и RANGE
ROWS считает физические строки; RANGE считает по логическому значению столбца сортировки и объединяет одинаковые значения в группы равных строк. Рамка по умолчанию для OVER (ORDER BY ...) — это RANGE, поэтому наивная текущая сумма может объединить одинаковые значения сортировки.
Выбирайте ROWS для «последних N записей» и скользящих окон, нечувствительных к пропускам; выбирайте RANGE со смещением для «последних N дней/долларов», когда нужно учитывать пропуски. Знание о существовании GROUPS будет дополнительным плюсом. Далее мы применим рамку ROWS для построения скользящих средних.
Часто задаваемые вопросы
Урок «Рамки ROWS и RANGE» бесплатный?
Да — полный текст урока «Рамки ROWS и RANGE» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Interview Prep, подпишись на CoddyKit PRO. Курс SQL Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Рамки ROWS и RANGE»?
Разбирайте тонкое и часто проверяемое различие между рамками по строкам и по значениям. Ты практикуешь SQL Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать SQL Interview Prep?
Предыдущий опыт не требуется. SQL Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Рамки ROWS и RANGE»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке SQL Interview Prep?
Да. Каждый урок SQL Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Накопительные суммы с оконными рамками
- Рамки ROWS и RANGE
- Скользящие средние в скользящем окне
- Накопительное распределение и доля от общего