Xorthax has now seen totals that build over time. But sometimes a running total gets too large to be useful.
Instead of asking “how much so far?”, he wants to ask:
“What’s the average over the last few rows?”
That’s a rolling average.
A rolling average calculates an average across a small window that moves row by row.
AVG(column) OVER (
ORDER BY column
ROWS BETWEEN n PRECEDING AND CURRENT ROW
)
This works because:
ORDER BY defines the sequence| OrderDate | Amount |
|---|---|
| 2024-01-01 | 100 |
| 2024-01-05 | 150 |
| 2024-01-10 | 200 |
| 2024-01-15 | 50 |
SELECT OrderDate, Amount,
AVG(Amount) OVER (
ORDER BY OrderDate
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS RollingAvg
FROM Orders;
Result:
| OrderDate | Amount | RollingAvg |
|---|---|---|
| 2024-01-01 | 100 | 100.0 |
| 2024-01-05 | 150 | 125.0 |
| 2024-01-10 | 200 | 150.0 |
| 2024-01-15 | 50 | 133.3 |
Each row shows the average for a small moving window, not the entire dataset.
ORDER BY OrderDate puts the rows in sequence from earliest to latest.
Then the frame tells SQL which rows to include for each calculation.
In this example, the frame includes:
That means the window slides forward one row at a time.
Early rows use fewer values because there aren’t yet two previous rows available.
This is what makes rolling averages useful: they smooth out short-term ups and downs without using all rows in the table.
For each order, calculate the average totalamount over the current order and the two previous orders based on orderdate.
| Column | Type |
|---|---|
| orderid | bigint |
| customerid | bigint |
| orderdate | timestamp without time zone |
| totalamount | double precision |
| status | text |
| Column |
|---|
| orderid |
| orderdate |
| totalamount |
| rolling_avg |
So far, you’ve used the most common frame patterns.
Next, you’ll look at more window frame options, including ways to look forward and define broader ranges.