¿Cómo comparo cada fila con la del mes anterior en SQL con LAG?
Trae las ventas del mes anterior a cada fila con LAG y calcula cuánto subieron o bajaron.
Curso gratis. Tu Maestro, una IA, .
"¿Cuánto vendimos más que el mes pasado?" Para restar, necesitas las ventas del mes anterior en la misma fila que las del mes actual. LAG hace exactamente eso: trae un valor de la fila anterior de su partición.
LAG(ventas)traeventasde la fila anterior.LEAD(ventas)traeventasde la fila siguiente.OVER (PARTITION BY sucursal ORDER BY mes)dice qué es "anterior": el mes previo de la misma sucursal.
Si no le dices más, LAG mira una fila atrás y, cuando no hay fila anterior, regresa NULL.
ventas - LAG(ventas) OVER (
PARTITION BY sucursal
ORDER BY mes
) AS cambioInténtalo
Antes de escribir la consulta, contesta la pregunta de abajo. Luego corre tu consulta y revisa tu respuesta en la fila de enero. Si los números de una sucursal se mezclan con los de otra, pregúntale a tu Maestro.
Comprueba lo que sabes: Antes de correr: ¿qué sale en la columna cambio en la fila de enero de Centro?
Regresa sucursal, mes, ventas, ventasanterior (las ventas de la fila anterior de la misma sucursal, con LAG) y cambio (ventas menos ventasanterior). Ordena por sucursal, mes. Terminaste cuando ves 35 filas y febrero de Centro dice 165100 y -9400.
Tu turno
Regresa sucursal, mes, ventas, ventas_anterior (las ventas de la fila anterior de la misma sucursal, con LAG) y cambio (ventas menos ventas_anterior). Ordena por sucursal, mes. Terminaste cuando ves 35 filas y febrero de Centro dice 165100 y -9400.
Tablas: ventas_mensuales (sucursal, mes, ventas)
ventas_mensuales · 35 filas
| Columna | Tipo |
|---|---|
| sucursal Nombre de la sucursal: Centro, Norte o Sur. | VARCHAR |
| mes Primer día del mes que resume la fila. | DATE |
| ventas Ventas del mes, en pesos. | BIGINT |
Primeras filas
| sucursal | mes | ventas |
|---|---|---|
| Centro | 2025-01-01 | 165100 |
| Centro | 2025-02-01 | 155700 |
| Centro | 2025-03-01 | 178700 |
Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras. Tab agrega sangría; para salir del editor, presiona Escape y luego Tab.
Listo para ejecutar tu consulta.
Fila por fila
Así quedaron los primeros meses de Centro al correr la solución en el sandbox de Maestro. Lee la tabla en diagonal: el ventas de una fila baja a la columna ventas_anterior de la fila siguiente.
| mes | ventas | ventas_anterior | cambio |
|---|---|---|---|
| 2025-01-01 | 165100 | NULL | NULL |
| 2025-02-01 | 155700 | 165100 | -9400 |
| 2025-03-01 | 178700 | 155700 | 23000 |
| 2025-04-01 | 175800 | 178700 | -2900 |
LAG no busca "el mes pasado" en el calendario. Hace algo más simple: dentro de la partición de Centro, ordenada por mes, toma la fila que está justo arriba. Cuando la consulta pasa a la primera fila de Norte, no hay fila arriba dentro de Norte, y por eso enero de Norte también recibe NULL.
La gráfica dibuja la columna cambio de Centro. Vega-Lite tiene su propia ventana con lag, y la gráfica la usa para calcular cada barra a partir de las ventas.
En enero sale NULL en las dos columnas nuevas: es la primera fila de su sucursal, así que no hay fila anterior. Y cualquier resta con NULL da NULL. Eso es correcto: no sabes cuánto cambió enero porque la tabla no tiene diciembre de 2024.
Gracias al PARTITION BY sucursal, enero de Norte no se compara con diciembre de Centro. Sin él, las tres sucursales serían una sola fila tras otra.
Lo que cambia el número
El 0 que parece inocente. LAG acepta un tercer argumento: el valor que regresa cuando no hay fila anterior. Es tentador escribir LAG(ventas, 1, 0) para no ver NULL. En el sandbox, con esa versión, enero de Centro reportó un cambio de 165100: parece que la sucursal creció todo lo que vendió. Un NULL dice "no sé"; un 0 inventado dice algo falso. Deja el NULL, o explícalo en el reporte.
El porcentaje. Casi nunca te piden la resta, te piden "cuánto creció en porcentaje": el cambio entre las ventas anteriores. En la corrida, febrero de Centro dio -5.7 y marzo 14.8. Cuando la misma ventana aparece tres veces, la cláusula WINDOW le pone nombre una sola vez, y DuckDB la aceptó tal cual (abajo). Si el valor anterior puede ser 0, protege la división con NULLIF(LAG(ventas) OVER w, 0).
Un empate en el orden. Si dos filas de la partición comparten el valor del ORDER BY, cuál es "la anterior" no está garantizado, igual que con ROW_NUMBER. Desempata con una columna que no se repita.
Hacia adelante. LEAD funciona igual en la otra dirección: en la corrida, LEAD(ventas) en enero de Centro trajo 155700, el de febrero, y en diciembre dio NULL porque no hay mes siguiente.
SELECT sucursal, mes, ventas,
ventas - LAG(ventas) OVER w AS cambio,
ROUND(100.0 * (ventas - LAG(ventas) OVER w)
/ LAG(ventas) OVER w, 1) AS pct_cambio
FROM ventas_mensuales
WINDOW w AS (PARTITION BY sucursal ORDER BY mes)
ORDER BY sucursal, mes;Si te toca en una entrevista, puede sonar a "calcula el crecimiento mes contra mes de cada producto", "¿cuántos días pasaron entre cada compra de un usuario y la anterior?" o "encuentra a los usuarios que compraron dos días seguidos". Las tres son LAG con la partición correcta. La de los días es la misma idea con fechas: restas la fecha de la fila anterior. En la tabla pedidos, Elena tiene dos pedidos el 6 de febrero, así que el segundo dio 0 días, y su pedido 1028 llegó 15 días después del anterior. Si quieres practicar una de estas en voz alta, pídele a tu Maestro que te la pregunte.
En tus reportes: busca uno que compare "contra el periodo anterior" y revisa cómo lo calcula. Si hoy alguien copia la columna del mes pasado a mano o hace una unión de la tabla consigo misma, LAG lo resuelve en una línea. Y antes de entregarlo, lee la página siguiente: un mes que falta cambia lo que significa "anterior".
SELECT cliente, pedido_id, fecha,
fecha - LAG(fecha) OVER (
PARTITION BY cliente
ORDER BY fecha, pedido_id
) AS dias_desde_el_anterior
FROM pedidos
ORDER BY cliente, fecha, pedido_id;