CoreTrail

Window frames

Choose exactly which rows participate in a calculation.

CorePostgreSQL5 min read
On this page

Explore the moving frame

Change the current row and the frame. Highlighted cells are included in the sum; the outlined cell is the current row.

Here, BETWEEN specifies frame boundaries. It does not filter output rows like WHERE amount BETWEEN ....

SUM(revenue) OVER (
    ORDER BY sale_date
    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)

Interpret this as: order the rows by date, then sum the current row and up to two rows before it.

Boundary Meaning with ROWS
UNBOUNDED PRECEDING Start of the partition
2 PRECEDING Two row positions before the current row
CURRENT ROW This row
2 FOLLOWING Two row positions after the current row
UNBOUNDED FOLLOWING End of the partition

Frame recipes to remember

Frame Typical use
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW Running total
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW Three-row trailing calculation
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING Previous three rows, excluding current
ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING Current and next two rows
ROWS BETWEEN 1 FOLLOWING AND 3 FOLLOWING Next three rows, excluding current
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING Centered calculation
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING Remaining total from current row onward
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING Entire partition

Worked example with visible outputs

WITH sample(day_no, revenue) AS (
    VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50)
)
SELECT day_no, revenue,
       SUM(revenue) OVER (
           ORDER BY day_no
           ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS running_total,
       SUM(revenue) OVER (
           ORDER BY day_no
           ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
       ) AS trailing_3,
       SUM(revenue) OVER (
           ORDER BY day_no
           ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING
       ) AS forward_3,
       SUM(revenue) OVER (
           ORDER BY day_no
           ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
       ) AS centered_3
FROM sample
ORDER BY day_no;
day_no revenue running_total trailing_3 forward_3 centered_3
1 10 10 10 60 30
2 20 30 30 90 60
3 30 60 60 120 90
4 40 100 90 90 120
5 50 150 120 50 90

At row 4, a three-row forward frame contains only rows 4 and 5. Frames stop at partition boundaries; SQL does not invent missing rows.

AVG averages the available non-null inputs, not a fixed denominator of three. An empty frame gives null for SUM/AVG and zero for COUNT.

Direction follows ORDER BY: with ORDER BY sale_date DESC, preceding rows have later dates. PRECEDING does not inherently mean earlier in chronological time.

References

Type a concept, keyword, or function.