SQL Window Functions: Running Totals, Moving Averages, and Cumulative Metrics

Rolling metrics, cumulative sums, moving averages, and period-over-period analytics with frame clauses.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all

Running metrics

Cumulative calculations are often the first real analytic use case.

Running total

Cumulative sum ordered by date.

sqlANYrunning-total
sql
SELECT order_date,
       amount,
       SUM(amount) OVER (
         ORDER BY order_date
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS running_total
FROM daily_sales;

Always specify the frame explicitly when you want a deterministic row-by-row cumulative total.

Running count

Count rows seen so far.

sqlANYrunning-count
sql
SELECT event_time,
       user_id,
       COUNT(*) OVER (
         ORDER BY event_time
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS running_events
FROM events;

Helpful for event streams and operational dashboards.

Cumulative maximum

Track the best-so-far value.

sqlANYmax
sql
SELECT measured_at,
       temperature,
       MAX(temperature) OVER (
         ORDER BY measured_at
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS max_so_far
FROM sensor_readings;

Cumulative max and min are compact ways to model records or thresholds.

Moving windows

Smooth noisy data with bounded frames.

3-row moving average

Average current row and previous two rows.

sqlANYmoving-average
sql
SELECT day,
       revenue,
       AVG(revenue) OVER (
         ORDER BY day
         ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
       ) AS moving_avg_3
FROM daily_revenue;

A row-based moving average is stable when each row is one time bucket.

7-row moving sum

Rolling weekly sum on daily rows.

sqlANYmoving-sum
sql
SELECT day,
       revenue,
       SUM(revenue) OVER (
         ORDER BY day
         ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
       ) AS moving_sum_7
FROM daily_revenue;

This is a common KPI smoothing pattern for dashboards.

Centered moving average

Use prior and following rows together.

sqlANYcentered
sql
SELECT day,
       value,
       AVG(value) OVER (
         ORDER BY day
         ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
       ) AS centered_avg_3
FROM metrics;

A centered frame is useful for smoothing but depends on future rows being present.

Running total per category

Reset the running total by partition.

sqlANYpartitionedtime-series
sql
SELECT month,
       region,
       sales,
       SUM(sales) OVER (
         PARTITION BY region
         ORDER BY month
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS regional_running_total
FROM monthly_sales;

Combining `PARTITION BY` and `ORDER BY` is the backbone of grouped time-series analysis.

Recommended next

No recommendations yet.