LAG / LEAD
Read a value from a previous or following row without a self-join.
Syntax
LAG(expression [, offset [, default]]) OVER (
[PARTITION BY partition_expression, ...]
ORDER BY sort_expression [ASC | DESC], ...
)
LEAD(expression [, offset [, default]]) OVER ( ... )What it does
LAG() returns expression from the row offset positions before the current row in the window order; LEAD() looks offset positions after. offset defaults to 1. When there is no such row the result is default, or NULL if no default is given.
Example
SELECT
month,
revenue,
revenue - LAG(revenue) OVER (ORDER BY month) AS mom_change
FROM monthly_revenue;Per-group comparison
SELECT
customer_id,
order_date,
order_date - LAG(order_date) OVER (
PARTITION BY customer_id
ORDER BY order_date
) AS days_since_previous
FROM orders;Common pitfalls
- the first row of each partition has no prior row —
LAGreturnsNULL(or yourdefault) there, and subtracting from it yieldsNULL - the window
ORDER BYdefines "previous"; without a stable tiebreaker, ties make the neighbour arbitrary PARTITION BYresets the lookback at each group boundary — leave it out only if you really want to read across groups
Safety check before shipping
- decide what the boundary rows should show —
NULL,0, or a supplied default - confirm the window
ORDER BYis deterministic - check whether the comparison should reset per partition