Memra

Running totals and LAG

◈ 2 cards

Frames, cumulative sums, and the previous row.

Cumulative and relative

Add ORDER BY to a windowed SUM and it becomes a running total — each row sums itself and all prior rows in the window:

SELECT ordered_at, id,
       SUM(1) OVER (ORDER BY ordered_at, id) AS orders_so_far
FROM orders;

LAG(col) peeks at the previous row's value (and LEAD the next) — perfect for deltas, e.g. days since the prior order. LAG returns NULL on the first row, since there's nothing before it.

ordered_atidorders_so_farprev_date2023-02-0111NULL2023-02-03222023-02-012023-03-10332023-02-032023-03-12442023-03-102023-04-01552023-03-12LAG has nothing to look back at on the first row.
Both columns come from the same window, ORDER BY ordered_at, id. The running count reads every row up to this one; LAG reads exactly one row back — and there is nothing behind the first row, so it is NULL.
titlegenrepriceROWSRANGEPaper Boatschildren7.507.507.50The GlassForestfiction14.9922.4951.74Rivers of Saltfiction16.0038.4951.74Bright Hollowfiction13.2551.7451.74RANGE lumps peer rows; ROWS counts one at a time.
ROWS is SUM(price) OVER (ORDER BY genre, id ROWS UNBOUNDED PRECEDING); RANGE is SUM(price) OVER (ORDER BY genre), the default. RANGE treats every row with the same ORDER BY value as one peer group, so all three fiction rows already carry the whole genre.
NORMAL ~/memra/learn/postgresql/running-totals utf-8 LF