Дело о длинном тире
Невероятные приключения здравого смысла среди борцов с ИИ
Сатирическая история о творчестве, бдительности и людях, которые точно знают, как сделать лучше.
Осторожно: может пострадать ваш здравый смысл.

Семь строк в SQL — ещё не семь дней. Как пропуски дат меняют скользящую сумму
Для показателя «за последние семь дней» легко написать:
SUM(amount) OVER ( ORDER BY day ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
)Но ROWS отсчитывает строки. Если в таблице нет дней без продаж, семь соседних строк могут охватывать несколько недель.
Проверим на учебном примере для SQLite. В таблице одна строка на день с продажами; в остальные дни продаж действительно не было. Суммы для простоты записаны в рублях.
WITH daily(day, amount) AS ( VALUES ('2026-10-01', 10), ('2026-10-09', 20), ('2026-10-10', 30)
)
SELECT day, SUM(amount) OVER ( ORDER BY day ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ) AS sum_by_rows, SUM(amount) OVER ( ORDER BY julianday(day) RANGE BETWEEN 6 PRECEDING AND CURRENT ROW ) AS sum_by_days
FROM daily
ORDER BY day;Результат:

Для 10 октября нужный период — с 4 по 10 октября включительно. Продажа 1 октября в него не входит, поэтому сумма равна 50. Окно по строкам захватывает все три имеющиеся записи и возвращает 60.
В варианте с RANGE функция julianday(day) даёт числовую шкалу дней. Граница 6 PRECEDING охватывает текущий день и шесть предыдущих. Здесь используются корректные даты без времени; для временных меток сначала нужно определить часовой пояс отчёта и получить дневные итоги.
Есть и второй способ: дополнить таблицу календарём, чтобы каждому дню соответствовала строка, а подтверждённому отсутствию продаж — ноль. Тогда ROWS снова будет отсчитывать дни. Это также позволит показать на графике даты без продаж.
Для средней за семь календарных дней различие ещё заметнее. Если в том же семидневном окне заменить SUM(amount) на AVG(amount), на 10 октября получится 25 ₽: среднее по двум строкам за 9 и 10 октября. А среднее за все семь календарных дней — 50 / 7 ≈ 7,14 ₽. Этот расчёт предполагает, что данные за все семь дней полные. Для сравнения: обычный AVG(amount) по всей исходной таблице дал бы 20 ₽.
RANGE ограничивает окно, но не создаёт строки для пропущенных дат. Поэтому и в результате запроса остаются только даты, которые есть во входных данных.
Отсутствие строки из-за сбоя загрузки нельзя автоматически приравнивать к нулевым продажам. Иначе календарь сделает результат аккуратным, но неверным.
Перед проверкой формулы по идее надо проверить, что означает одна строка таблицы. Для скользящих показателей это напрямую определяет границы расчёта.

Невероятные приключения здравого смысла среди борцов с ИИ
Сатирическая история о творчестве, бдительности и людях, которые точно знают, как сделать лучше.
Осторожно: может пострадать ваш здравый смысл.
