Windows II — frames & running
Concept  ·  SQL & Querying

ROWS 6 PRECEDING is the last 7 rows; a rolling 7-day metric needs RANGE INTERVAL '6 days' (or a date spine) — they agree only at one row per entity per day.

A window frame is either row-based or time-based. ROWS counts a fixed number of preceding rows; it cannot see a calendar gap between two rows. RANGE with an interval counts a span of time, so gaps are respected.

See it break
txns
user_idtxn_dateamount
422024-01-0110
422024-01-0930
422024-01-105
The trap
SELECT
  txn_date,
  SUM(amount) OVER (
    PARTITION BY
      user_id
    ORDER BY
      txn_date ROWS BETWEEN 6 PRECEDING
      AND CURRENT ROW
  ) AS rolling
FROM
  txns
ORDER BY
  txn_date;
The fix
SELECT
  txn_date,
  SUM(amount) OVER (
    PARTITION BY
      user_id
    ORDER BY
      txn_date RANGE BETWEEN INTERVAL '6 days' PRECEDING
      AND CURRENT ROW
  ) AS rolling
FROM
  txns
ORDER BY
  txn_date;
INPUTYour queryThe fix
2024-01-011010
2024-01-094030
2024-01-104535

Wrong by $10, no error raised, and every calendar gap makes it worse.

The rule

Use RANGE BETWEEN INTERVAL '6 days' PRECEDING, or pre-aggregate to one row per entity per day so a ROWS frame is honest again.

RANGE BETWEEN INTERVAL '<N> days' PRECEDING AND CURRENT ROW

Where RANGE with intervals is unsupported, the per-day date-spine form is the portable equivalent.

Shows up elsewhere
Moving-average edgesRolling windows over gapped dates
Try one →Prove it in practice →