LAG y LEAD: la fila anterior y la siguiente
Intermediolag(columna) devuelve el valor de la fila anterior y lead(columna) el de la siguiente, según el ORDER BY de la ventana. Con PARTITION BY la comparación no cruza de un grupo a otro. Sirven para variaciones contra el período anterior y para medir el tiempo entre eventos.
Sintaxis
lag(valor) OVER (PARTITION BY grupo ORDER BY fecha) -- fila anterior
lag(valor, 1, 0) OVER (PARTITION BY grupo ORDER BY fecha) -- 0 si no hay anterior
lead(valor, 7) OVER (PARTITION BY grupo ORDER BY fecha) -- siete filas despuésEjemplo
SELECT
currency AS moneda,
to_char(rate_date, 'YYYY-MM-DD') AS dia,
usd_rate,
lag(usd_rate) OVER (PARTITION BY currency ORDER BY rate_date) AS dia_anterior,
usd_rate - lag(usd_rate) OVER (PARTITION BY currency ORDER BY rate_date) AS variacion,
lead(usd_rate) OVER (PARTITION BY currency ORDER BY rate_date) AS dia_siguiente
FROM fx_rates
WHERE currency IN ('UYU', 'CLP')
AND rate_date >= '2025-08-01'
AND rate_date < '2025-08-05'
ORDER BY moneda, rate_date;Resultado
| moneda | dia | usd_rate | dia_anterior | variacion | dia_siguiente |
|---|---|---|---|---|---|
| CLP | 2025-08-01 | 527.8600 | NULL | NULL | 527.4100 |
| CLP | 2025-08-02 | 527.4100 | 527.8600 | -0.4500 | 529.0800 |
| CLP | 2025-08-03 | 529.0800 | 527.4100 | 1.6700 | 531.2300 |
| CLP | 2025-08-04 | 531.2300 | 529.0800 | 2.1500 | NULL |
| UYU | 2025-08-01 | 22.5300 | NULL | NULL | 22.5400 |
| UYU | 2025-08-02 | 22.5400 | 22.5300 | 0.0100 | 22.5600 |
| UYU | 2025-08-03 | 22.5600 | 22.5400 | 0.0200 | 22.5400 |
| UYU | 2025-08-04 | 22.5400 | 22.5600 | -0.0200 | NULL |
Cómo leerlo
Cada moneda es su propia partición, así que el 1 de agosto del peso uruguayo no se compara con el 4 de agosto del peso chileno. El primer día de cada moneda tiene dia_anterior en NULL, aunque la tabla sí tiene el 31 de julio: el WHERE se aplica antes que la ventana. Si necesitas ese valor, calcula el lag en una CTE sobre un rango más amplio y filtra después.
Error común
Así no
SELECT currency, rate_date, usd_rate,
usd_rate - lag(usd_rate) OVER (ORDER BY currency, rate_date) AS variacion
FROM fx_rates
WHERE currency IN ('UYU', 'CLP');Olvidar el PARTITION BY. Sin él, la primera fila del peso uruguayo toma como anterior la última del peso chileno y la variación mezcla dos monedas. También conviene revisar el valor por defecto: lag(usd_rate, 1, 0) evita el NULL, pero convierte la primera variación en el tipo de cambio completo.