LEAD

LEAD es la función complementaria de LAG: mientras LAG mira hacia atrás, LEAD mira hacia adelante. Permite acceder al valor de una fila posterior dentro de la misma partición sin necesidad de un JOIN. Es especialmente útil para análisis prospectivos: calcular cuánto tiempo falta hasta el próximo evento, anticipar cambios futuros o comparar cada registro con su sucesor.

En muchos escenarios analíticos, saber qué viene después es tan valioso como saber qué pasó antes. LEAD te permite responder preguntas como "cuánto tiempo pasará hasta la próxima compra de este cliente" o "cuánto subirá el precio en el siguiente periodo" directamente en la consulta.

Sintaxis

LEAD(expresion, offset, valor_defecto) OVER (
    [PARTITION BY columna1, columna2, ...]
    ORDER BY columna1 [ASC|DESC], columna2 [ASC|DESC], ...
)

Los argumentos son idénticos a los de LAG. La expresion es la columna cuyo valor futuro quieres obtener. El offset indica cuántas filas adelante mirar (por defecto 1). El valor_defecto es lo que se devuelve cuando no existe fila siguiente (por defecto NULL). El ORDER BY es imprescindible porque sin él, "siguiente" no tiene significado.

Comportamiento básico

En su forma más simple, LEAD devuelve el valor de la columna indicada en la fila siguiente:

SELECT
    mes,
    ingresos,
    LEAD(ingresos) OVER (ORDER BY mes) AS ingresos_mes_siguiente
FROM resumen_mensual
WHERE anio = 2024
ORDER BY mes;
mesingresosingresos_mes_siguiente
157000.0051750.00
251750.0065600.00
365600.0072250.00
472250.0067660.00
567660.0079200.00
679200.00NULL

Enero muestra los ingresos de febrero como "siguiente". Junio, al ser el último mes del resultado, no tiene sucesor y devuelve NULL. La mecánica es el espejo exacto de LAG: donde LAG mira una fila hacia arriba, LEAD mira una fila hacia abajo.

Valor por defecto y offset

Puedes especificar un offset mayor que 1 y un valor por defecto para la última fila:

SELECT
    mes,
    ingresos,
    LEAD(ingresos, 1, 0) OVER (ORDER BY mes) AS siguiente,
    LEAD(ingresos, 2) OVER (ORDER BY mes) AS dos_meses_despues
FROM resumen_mensual
WHERE anio = 2024
ORDER BY mes
LIMIT 4;
mesingresossiguientedos_meses_despues
157000.0051750.0065600.00
251750.0065600.0072250.00
365600.0072250.0067660.00
472250.0067660.0079200.00

Enero puede ver tanto los ingresos de febrero (offset 1) como los de marzo (offset 2). El valor por defecto de 0 solo aplica cuando no hay fila siguiente disponible.

Caso práctico: tiempo hasta el próximo pedido

Un análisis valioso para el equipo comercial es saber cuántos días pasan entre compras de cada cliente. LEAD permite calcular esto directamente:

SELECT
    c.nombre,
    p.fecha_pedido,
    LEAD(p.fecha_pedido) OVER (
        PARTITION BY p.id_cliente
        ORDER BY p.fecha_pedido
    ) AS siguiente_pedido,
    DATEDIFF(
        LEAD(p.fecha_pedido) OVER (
            PARTITION BY p.id_cliente
            ORDER BY p.fecha_pedido
        ),
        p.fecha_pedido
    ) AS dias_hasta_siguiente
FROM pedidos p
    JOIN clientes c ON p.id_cliente = c.id_cliente
WHERE c.nombre = 'Ana García'
ORDER BY p.fecha_pedido;
nombrefecha_pedidosiguiente_pedidodias_hasta_siguiente
Ana García2024-01-152024-02-2238
Ana García2024-02-222024-04-1048
Ana García2024-04-102024-05-0323
Ana García2024-05-032024-07-1876
Ana García2024-07-18NULLNULL

Ana compra cada 38, 48, 23 y 76 días. El último pedido muestra NULL porque no hay compra posterior en los datos. El PARTITION BY id_cliente garantiza que LEAD solo mire dentro de los pedidos del mismo cliente, no salte al siguiente.

Caso práctico: calcular la duración entre eventos

Otro escenario frecuente es calcular la duración de estados o periodos. Si tienes un registro de cambios de estado de un pedido, LEAD te permite saber cuánto duró cada estado:

SELECT
    id_pedido,
    estado,
    fecha_cambio,
    LEAD(fecha_cambio) OVER (
        PARTITION BY id_pedido
        ORDER BY fecha_cambio
    ) AS fecha_siguiente_estado,
    TIMESTAMPDIFF(
        HOUR,
        fecha_cambio,
        LEAD(fecha_cambio) OVER (
            PARTITION BY id_pedido
            ORDER BY fecha_cambio
        )
    ) AS horas_en_estado
FROM historial_pedidos
WHERE id_pedido = 5023;
id_pedidoestadofecha_cambiofecha_siguiente_estadohoras_en_estado
5023Recibido2024-03-15 09:00:002024-03-15 09:45:000
5023Procesando2024-03-15 09:45:002024-03-15 14:30:004
5023Empaquetado2024-03-15 14:30:002024-03-16 08:00:0017
5023Enviado2024-03-16 08:00:002024-03-18 11:20:0051
5023Entregado2024-03-18 11:20:00NULLNULL

El pedido pasó de "Recibido" a "Procesando" en menos de una hora, estuvo en proceso 4 horas, fue empaquetado durante 17 horas (incluye la noche), y tardó 51 horas en ser entregado tras el envío. El estado final "Entregado" no tiene siguiente porque es el estado terminal.

Caso práctico: análisis de escalones de precios

LEAD permite analizar incrementos de precios futuros, útil para estrategias comerciales:

SELECT
    nombre,
    fecha_precio,
    precio,
    LEAD(precio) OVER (
        PARTITION BY id_producto
        ORDER BY fecha_precio
    ) AS precio_siguiente,
    LEAD(fecha_precio) OVER (
        PARTITION BY id_producto
        ORDER BY fecha_precio
    ) AS fecha_cambio,
    ROUND(
        (LEAD(precio) OVER (PARTITION BY id_producto ORDER BY fecha_precio) - precio)
        / precio * 100,
        2
    ) AS variacion_pct
FROM historial_precios
WHERE nombre = 'Monitor 27" 4K'
ORDER BY fecha_precio;
nombrefecha_precioprecioprecio_siguientefecha_cambiovariacion_pct
Monitor 27" 4K2023-01-01399.00379.002023-06-15-5.01
Monitor 27" 4K2023-06-15379.00349.002024-01-01-7.92
Monitor 27" 4K2024-01-01349.00329.002024-08-20-5.73
Monitor 27" 4K2024-08-20329.00NULLNULLNULL

La tendencia muestra que el monitor ha ido bajando de precio consistentemente entre un 5% y un 8% en cada ajuste.

Comparación con LAG

LEAD y LAG son simétricas: todo lo que puedes hacer con una, puedes hacerlo con la otra invirtiendo el orden. LAG(x) OVER (ORDER BY mes ASC) produce el mismo resultado que LEAD(x) OVER (ORDER BY mes DESC). La elección entre una y otra es cuestión de legibilidad según la pregunta que respondas. Si piensas en "qué pasó antes", usa LAG. Si piensas en "qué viene después", usa LEAD:

SELECT
    mes,
    ingresos,
    LAG(ingresos) OVER (ORDER BY mes) AS mes_anterior,
    LEAD(ingresos) OVER (ORDER BY mes) AS mes_siguiente
FROM resumen_mensual
WHERE anio = 2024
ORDER BY mes
LIMIT 4;
mesingresosmes_anteriormes_siguiente
157000.00NULL51750.00
251750.0057000.0065600.00
365600.0051750.0072250.00
472250.0065600.0067660.00

Manejo de NULL

El comportamiento de LEAD con NULL es idéntico al de LAG. Si la fila siguiente contiene NULL en la columna referenciada, LEAD devuelve NULL. No salta filas con NULL para buscar el siguiente valor no nulo:

SELECT
    mes,
    ingresos,
    LEAD(ingresos) OVER (ORDER BY mes) AS siguiente
FROM resumen_mensual;

Si el mes 3 tiene ingresos NULL, entonces LEAD(ingresos) para el mes 2 devolverá NULL, porque está reflejando fielmente el valor de la fila siguiente. Para sustituirlo por un valor seguro, usa COALESCE(LEAD(ingresos) OVER (...), 0).

Combinación con otras funciones

LEAD se combina con funciones condicionales para crear alertas y análisis predictivos:

SELECT
    mes,
    ingresos,
    LEAD(ingresos) OVER (ORDER BY mes) AS siguiente,
    CASE
        WHEN LEAD(ingresos) OVER (ORDER BY mes) IS NULL
            THEN 'Último periodo'
        WHEN LEAD(ingresos) OVER (ORDER BY mes) > ingresos
            THEN CONCAT('Sube a ', FORMAT(LEAD(ingresos) OVER (ORDER BY mes), 2))
        WHEN LEAD(ingresos) OVER (ORDER BY mes) < ingresos
            THEN CONCAT('Baja a ', FORMAT(LEAD(ingresos) OVER (ORDER BY mes), 2))
        ELSE 'Se mantiene'
    END AS prevision
FROM resumen_mensual
WHERE anio = 2024
ORDER BY mes;
mesingresossiguienteprevision
157000.0051750.00Baja a 51,750.00
251750.0065600.00Sube a 65,600.00
365600.0072250.00Sube a 72,250.00
472250.0067660.00Baja a 67,660.00
567660.0079200.00Sube a 79,200.00
679200.00NULLÚltimo periodo

Esta consulta genera un informe narrativo donde cada periodo indica si el siguiente sube o baja, proporcionando contexto inmediato sin necesidad de mirar los números en bruto.

Practica con LEAD

Usa el editor para acceder a filas siguientes:

Simulador SQL
Ctrl+Enter para ejecutar

En el siguiente artículo veremos FIRST_VALUE para obtener el primer valor de la ventana.

Escrito por Eduardo Lázaro