¿Por qué LAG se salta un mes que falta y cómo lo encuentro?
Descubre que LAG trae la fila anterior, no el mes anterior, y encuentra el hueco en los datos de Sur.
Curso gratis. Tu Maestro, una IA, .
En la página anterior, el cambio de julio en Sur fue -2000. Parece una baja pequeña respecto a junio. Pero la tabla no tiene junio para Sur: tiene 11 filas, no 12. ¿Contra qué se comparó julio?
Contra mayo. LAG trae la fila anterior de la partición, sin saber nada de calendarios. Si falta una fila, compara con la que sí está. Nada en el resultado te avisa: el -2000 se ve igual de confiable que los demás.
Cuidado: LAG cuenta filas, no meses
Un mes que falta no aparece como NULL: simplemente no hay fila. Antes de reportar un "cambio respecto al mes anterior", comprueba que la fila anterior de verdad sea el mes anterior.
Fila por fila
Estas son las filas de Sur de abril a agosto en la consulta de la página anterior, tal como salieron en el sandbox:
| mes | ventas | ventas_anterior | cambio |
|---|---|---|---|
| 2025-04-01 | 121000 | 112700 | 8300 |
| 2025-05-01 | 119600 | 121000 | -1400 |
| 2025-07-01 | 117600 | 119600 | -2000 |
| 2025-08-01 | 122900 | 117600 | 5300 |
Fíjate en la columna mes: de mayo salta a julio. La partición de Sur tiene 11 filas, y para LAG la fila de julio está justo debajo de la de mayo, así que mayo es "la anterior". La consulta no se equivocó: hizo exactamente lo que le pediste. La pregunta es otra.
Pedidos que llegaron más de 14 días después del anterior
Ejemplo resuelto · 3 pasos
En la tabla pedidos, queremos los pedidos que llegaron más de 14 días después del pedido anterior del mismo cliente, con las dos fechas y los días de distancia. Es el mismo problema que vas a resolver con meses, pero con días.
Piensa el siguiente paso por tu cuenta y luego ábrelo para comparar.
La forma de comprobarlo con meses es la misma: traer también el mes de la fila anterior y medir la distancia. En DuckDB, date_diff('month', inicio, fin) cuenta los meses entre dos fechas: entre mayo y julio da 2.
Inténtalo
Encuentra todas las filas donde la fila anterior de su sucursal no es el mes anterior. Necesitas dos pasos, como en el ejemplo: calcular LAG(mes) y luego filtrar. Antes, contesta la pregunta de abajo. Si no sabes cómo dividirlo en dos pasos, pregúntale a tu Maestro.
Comprueba lo que sabes: Antes de correr: ¿cuántas filas va a regresar tu consulta de huecos sobre las 35 filas de ventas_mensuales?
Regresa sucursal, mes, mesanterior (el mes de la fila anterior de su sucursal, con LAG(mes)) y mesesdedistancia (con datediff('month', mesanterior, mes)), solo para las filas donde la distancia es mayor que 1. Ordena por sucursal, mes. Terminaste cuando encuentras el hueco de Sur
Tu turno
Regresa sucursal, mes, mes_anterior (el mes de la fila anterior de su sucursal, con LAG(mes)) y meses_de_distancia (con date_diff('month', mes_anterior, mes)), solo para las filas donde la distancia es mayor que 1. Ordena por sucursal, mes. Terminaste cuando encuentras el hueco de Sur.
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.
Una sola fila: julio de Sur, cuya fila anterior es mayo, a 2 meses de distancia. Y fíjate en enero: su mes_anterior es NULL, y date_diff con NULL da NULL, que no es mayor que 1. Por eso enero no sale en el resultado.
Con QUALIFY te ahorras el WITH, y además puedes usar el alias del SELECT. En el sandbox, esta versión regresó la misma fila que la solución:
SELECT sucursal, mes,
LAG(mes) OVER (PARTITION BY sucursal ORDER BY mes) AS mes_anterior,
date_diff('month', mes_anterior, mes) AS meses_de_distancia
FROM ventas_mensuales
QUALIFY meses_de_distancia > 1
ORDER BY sucursal, mes;Rellenar el calendario
Encontrar el hueco es la mitad. Si tu reporte necesita "contra el mes anterior" de verdad, la salida es darle a LAG una fila por cada mes, exista o no. Primero armas la lista completa de meses con generate_series, y después unes tus ventas con LEFT JOIN: el mes que no tiene ventas se queda con su fila y ventas en NULL.
WITH calendario AS (
SELECT CAST(m AS DATE) AS mes
FROM generate_series(DATE '2025-01-01', DATE '2025-12-01',
INTERVAL 1 MONTH) AS t(m)
),
sur AS (
SELECT c.mes, v.ventas
FROM calendario c
LEFT JOIN ventas_mensuales v
ON v.mes = c.mes AND v.sucursal = 'Sur'
)
SELECT mes, ventas,
LAG(ventas) OVER (ORDER BY mes) AS ventas_anterior,
ventas - LAG(ventas) OVER (ORDER BY mes) AS cambio
FROM sur
ORDER BY mes;En el sandbox, las filas de abril a agosto quedaron así:
| mes | ventas | ventas_anterior | cambio |
|---|---|---|---|
| 2025-04-01 | 121000 | 112700 | 8300 |
| 2025-05-01 | 119600 | 121000 | -1400 |
| 2025-06-01 | NULL | 119600 | NULL |
| 2025-07-01 | 117600 | NULL | NULL |
| 2025-08-01 | 122900 | 117600 | 5300 |
Ahora junio existe, aunque vacío, y julio ya no se compara con mayo: su cambio es NULL, que es la respuesta honesta. Si pasas v.sucursal = 'Sur' del ON al WHERE, la fila de junio se va: el WHERE corre después de la unión y descarta todo lo que no dice Sur. En el sandbox, esa versión regresó 11 filas, sin junio.
Preguntas de entrevista que esconden este hueco: "encuentra los huecos en esta serie", "¿qué usuarios dejaron de comprar más de 30 días?" o "¿qué días no hubo ninguna venta?". Las dos primeras son LAG más una distancia; la tercera es un calendario con LEFT JOIN. Si dices en voz alta que LAG cuenta filas y no fechas, ya mostraste lo que la pregunta busca. Si quieres revisar una serie tuya, cuéntale a tu Maestro cómo está tu tabla.
Antes de entregar cualquier "contra el periodo anterior", corre la búsqueda de huecos de esta página sobre tu tabla. Si sale vacía, tu LAG compara lo que dice comparar. Si sale algo, decide con quien lee el reporte: rellenar el calendario, o decir "contra mayo".