How do LEAD and LAG work?
LAG looks backwards and LEAD looks forwards. Both take an expression, an offset and an ordering, and they return the value of that expression from a neighbouring row of the same partition.
CREATE TABLE monthly_sales (
month TEXT PRIMARY KEY,
revenue DECIMAL(12, 2) NOT NULL
);
INSERT INTO monthly_sales (month, revenue) VALUES
('2026-01', 30000.00),
('2026-02', 64000.00),
('2026-03', 46500.00);
SELECT month,
revenue,
LAG(revenue) OVER (ORDER BY month) AS prev_month,
LEAD(revenue) OVER (ORDER BY month) AS next_month
FROM monthly_sales
ORDER BY month;Three rows come back. January has a NULL previous month and 64000.00 as the next; February has 30000.00 behind it and 46500.00 ahead; March has 64000.00 behind it and NULL ahead.
The NULLs are not errors. The first row of a partition has no previous row and the last has no next one, so the function has nothing to return and produces NULL. The default offset is 1, so LAG(x) is the previous row and LAG(x, 2) is the one two rows back. A third argument gives the value to use when there is no such row, so LAG(revenue, 1, 0) returns 0 instead of NULL for the first month.
Two things to be careful about. The ORDER BY inside the window is what defines "previous" and "next", and it has to be a total order — if two rows share the same month, which one is the previous row is not determined, so add a tiebreaker. And the expression you are lagging is evaluated in the frame of the current row, which is why you can lag a computed value such as LAG(revenue - LAG(revenue)) OVER (...) for a chained difference — though that is clearer as two separate window expressions.