Volver a la lista de artículos Artículos
Lectura de 11 minutos

Las funciones LAG y LEAD en SQL

LAG() y LEAD() son funciones posicionales. Una función posicional es una función de tipo ventana. Si no sabes cuándo o cómo usarlas, cuál es la sintaxis de cada función, por qué podrías querer usarlas y cuáles son las diferencias, ¡sigue leyendo!

LAG() y LEAD() son funciones posicionales. Son funciones de ventana y resultan muy útiles en la creación de informes, ya que pueden hacer referencia a datos de filas superiores o inferiores a la fila actual. En este artículo, veremos ambas en detalle.

Sintaxis de la función LAG

La función LAG() permite acceder a un valor almacenado en una fila diferente por encima de la fila actual. La fila superior puede ser adyacente o estar un número de filas por encima, ordenada por una columna o conjunto de columnas especificado.

Veamos su sintaxis:

LAG(expresión [,desplazamiento[,valor_predeterminado]]) OVER(ORDER BY columnas)

LAG() toma tres argumentos: el nombre de la columna o una expresión de la que se obtiene el valor, el número de filas a saltar (desplazamiento) por encima, y el valor predeterminado a devolver si el valor almacenado obtenido de la fila de arriba está vacío. Sólo se requiere el primer argumento. El tercer argumento (valor predeterminado) sólo se permite si se especifica el segundo argumento, el desplazamiento.

Al igual que otras funciones de ventana, LAG() requiere la cláusula OVER. Puede tomar parámetros opcionales, que explicaremos más adelante. Con LAG(), se debe especificar un ORDER BY en la cláusula OVER, con una columna o una lista de columnas por las que deben ordenarse las filas.

Consideremos la siguiente tabla, venta:

idnombre_vendedorvalor_venta
3Stef7000
1Alice12000
2Mili25000

Y la siguiente consulta con una función LAG():

SELECT nombre_vendedor, valor_venta,
  LAG(valor_venta) OVER(ORDER BY valor_venta) as valor_venta_anterior
FROM venta;

Este es el resultado:

nombre_vendedorvalor_ventavalor_venta_anterior
Stef7000NULL
Alice120007000
Mili2500012000

Este uso más sencillo de LAG() muestra el valor de la fila adyacente anterior. Por ejemplo, el segundo registro muestra el valor de la venta de Alice ($12.000) con el monto de la venta de Stef ($7.000) de la fila anterior, en las columnas valor_venta y valor_venta_anterior, respectivamente. Observa que la primera fila no tiene una fila adyacente por encima, y en consecuencia el campo valor_venta_anterior está vacío (NULL), ya que la fila de la que se debería obtener el valor de valor_venta no existe.

Si sólo se especifica el argumento requerido (el nombre de la columna u otra expresión), como hemos hecho en este ejemplo, el argumento del desplazamiento es 1 de manera predeterminada, y el tercer argumento es NULL de manera predeterminada. En nuestro ejemplo, la primera fila del conjunto de resultados tiene NULL en valor_venta_anterior y en las demás filas están los valores de las respectivas filas inmediatamente anteriores, porque el desplazamiento es 1.

Con LAG() se puede ver el valor de la fila actual, así como el valor de la fila adyacente anterior. Esto se puede utilizar, por ejemplo, para comprobar el valor de la venta de una fila determinada con el de la fila anterior, con el valor de la venta ordenado de menor a mayor.

La siguiente ilustración muestra cómo el valor de la fila adyacente anterior se añade a la fila actual.

Tabla

La función LAG() está incluida en nuestra práctica "Hoja de trucos SQL: Funciones de ventana".

Sintaxis de la función LEAD

LEAD() es similar a LAG(). Mientras que LAG() accede a un valor almacenado en una fila superior, LEAD() accede a un valor almacenado en una fila inferior.

La sintaxis de LEAD() es igual que la de LAG():

LEAD(expresión [,desplazamiento[,valor_predeterminado]]) OVER(ORDER BY columnas)

Al igual que LAG(), la función LEAD() toma tres argumentos: una expresión o el nombre de una columna, el desplazamiento que se debe saltar por debajo y el valor predeterminado que se debe devolver si el valor almacenado obtenido de la fila de abajo está vacío. Sólo se requiere el primer argumento. El tercer argumento, el valor predeterminado, sólo puede especificarse si se especifica el segundo argumento, el desplazamiento.

Al igual que LAG(), LEAD() es una función de ventana y requiere una cláusula OVER. Y al igual que LAG(), LEAD() debe ir acompañada de un ORDER BY en la cláusula OVER.

Volvamos a ver la tabla venta:

idnombre_vendedorvalor_venta
3Stef7000
1Alice12000
2Mili25000

He aquí una consulta con la función LEAD():

SELECT nombre_vendedor, valor_venta,
  LEAD(valor_venta) OVER(ORDER BY valor_venta) as valor_de_la_proxima_venta
FROM venta;

Este es el conjunto de resultados:

nombre_vendedorvalor_ventavalor_de_la_proxima_venta
Stef700012000
Alice1200025000
Mili25000NULL

Las filas están ordenadas por la columna especificada en ORDER BY (valor_venta). La función LEAD() toma el valor de la venta de la fila inferior. Por ejemplo, el valor de la venta del propio Stef es de $7.000 en la columna valor_venta, y la columna valor_de_la_proxima_venta del mismo registro contiene $12.000. Este último proviene de la columna valor_venta de Alice, la vendedora de la fila siguiente. Observa que la última fila no tiene una fila siguiente, por lo que el campo valor_de_la_proxima_venta está vacío (NULL) para la última fila.

Si especificas sólo el argumento requerido, es decir, sólo el nombre de la columna u otra expresión, el desplazamiento predeterminado es 1 y el tercer argumento predeterminado es NULL. En nuestro ejemplo, el valor para valor_de_la_proxima_venta de Alice es de la columna valor_venta de la fila adyacente inferior, ya que el desplazamiento predeterminado es 1.

Con LEAD() se pueden comparar valores entre filas. La siguiente ilustración muestra cómo la cantidad devuelta por LEAD() se añade a la fila actual.

Tabla

Uso de LAG() y LEAD() para comparar valores

Un uso importante de LAG() y LEAD() en informes es comparar los valores de la fila actual con los valores de la misma columna pero en una fila superior o inferior.

Consideremos la siguiente tabla, venta_anual, que se muestra a continuación:

añoventa_total
201523000
201625000
201734000
201832000
201933000

Como puedes ver, esta tabla contiene el valor total de las ventas por año. Utilizando LAG() y LEAD(), podemos comparar los importes de las ventas anuales entre años.

Veamos esta consulta:

SELECT  ano, venta_total_actual,
   LAG(venta_total) OVER(ORDER BY ano) AS venta_total_anterior,
   venta_total - LAG(venta_total) OVER(ORDER BY ano) AS diferencia
FROM venta_anual;

Este es el conjunto de resultados:

añoventa_total_actualventa_total_anteriordiferencia
201523000NULLNULL
201625000230002000
201734000250009000
20183200034000-2000
201933000320001000

Esta consulta toma el valor de las ventas del año anterior y lo pone en la columna venta_total_anterior utilizando la función LAG(). El ORDER BY en la cláusula OVER ordena los registros por año, asegurando que la fila adyacente de arriba representa el año anterior. A continuación, toma el valor de la columna venta_total_actual de la fila anterior y lo traslada a la fila actual.

Esta consulta también calcula la diferencia en el valor de las ventas entre el año actual y el anterior. Esto puede ayudarnos a entender si hubo un aumento (diferencia positiva) o una disminución (diferencia negativa) en las ventas de un año a otro.

Para 2015, no tenemos información sobre el año anterior. Por lo tanto, el valor devuelto por la función LAG() es NULL y también la diferencia. Ahora, la venta total en 2018 fue de $32.000 y de $34.000 en 2017 (el año anterior), como se muestra en la columna venta_total_anterior. La diferencia es de -$2.000, lo que indica que en 2018 hubo una disminución de las ventas de $2.000 en comparación con el año 2017.

Uso de LAG() y LEAD() con un desplazamiento específico

Puedes utilizar las funciones LAG() y LEAD() con dos argumentos: el nombre de la columna y el desplazamiento.

Consideremos la siguiente tabla, empleado:

id_del_empleadoañotrimestrebono
120171100
120172250
12017360
12017420
12018180
12018280
1201830
1201840
1201910
120192100
1201930
120194150

La siguiente consulta selecciona el bono del empleado con ID=1 para cada trimestre de cada año. A continuación, identifica los bonos del trimestre correspondiente del año anterior y del año posterior.

SELECT ano, trimestre,
  LAG(bono,4) OVER(ORDER BY ano,trimestre) AS bono_anterior,
 bono AS bono_actual,
  LEAD(bono,4) OVER(ORDER BY ano,trimestre) AS bono_siguiente
FROM empleado
WHERE id_del_empleado=1;

Esta consulta devuelve el siguiente conjunto de resultados:

añotrimestrebono_anteriorbono_actualbono_siguiente
20171NULL10080
20172NULL25080
20173NULL600
20174NULL200
20181100800
2018225080100
201836000
20184200150
20191800NULL
2019280100NULL
2019300NULL
201940150NULL

Las filas resaltadas en verde son los registros del primer trimestre de cada año, las filas en blanco el segundo trimestre de cada año, etc. En cualquier fila, los importes de los bonos anterior y siguiente se toman del trimestre correspondiente del año anterior y del año siguiente, se asignan a las columnas bono_anterior y bono_siguiente, respectivamente.

Por ejemplo, el empleado ID=1 recibió un bono de $80 en el primer trimestre de 2018. Para el mismo empleado, el bono del primer trimestre de 2017 fue de $100, y el bono del primer trimestre de 2019 fue de $0. ORDER BY especifica que las filas se ordenen por año y trimestre. Un desplazamiento de 4 indica a LEAD() y LAG() que se salten 4 filas antes y después de la fila actual, respectivamente. Con este desplazamiento, se pueden comparar valores del mismo trimestre de diferentes años, porque hay 4 trimestres en un año. La imagen siguiente ilustra esta idea.

Tabla

Puedes encontrar más información sobre las funciones LAG() y LEAD() en nuestros artículos "Funciones de ventana comunes en SQL: Funciones posicionales", de Aldo Zelen y "¿Cuándo se utilizan las Funciones de ventana en SQL?", de Tihomir Babic.

Uso de LAG() y LEAD() con un valor predeterminado

En la sección anterior, vimos cómo utilizar el argumento de desplazamiento en LAG() y LEAD(). Ahora, consideramos los casos con un tercer argumento: el valor predeterminado a asignar cuando el valor obtenido es NULL. Para especificar este argumento, se debe especificar también el segundo argumento, el desplazamiento. El desplazamiento predeterminado es 1, así que especifica 1 para mantener el desplazamiento predeterminado o algún otro valor apropiado para tu caso.

Veamos otro ejemplo. La siguiente tabla, venta_producto contiene los ID de los productos, el mes (1 = enero, 2 = febrero, etc.) y la cantidad de ventas por mes.

A continuación, se muestran los registros cuyo ID de producto es 1.

id_de_productomescantidad
11125
12135
13NULL
1490

La siguiente consulta:

SELECT id_de_producto, mes,
  LAG(cantidad,1,0) OVER(ORDER BY mes) AS cantidad_anterior,
  cantidad AS cantidad_actual,
  cantidad - LAG(cantidad,1,0) OVER(ORDER BY mes) AS diferencia
FROM venta_producto
WHERE id_de_producto=1;

Devuelve el siguiente resultado:

id_de_productomescantidad_anteriorcantidad_actualdiferencia
110125125
1212513510
13135NULLNULL
14NULL90NULL

Para el producto con ID=1, seleccionamos el mes de venta, la cantidad de ventas para este mes (cantidad_actual), y la cantidad de ventas del mes anterior (el valor de la fila anterior devuelto por LAG()).

Nos gustaría mostrar cero en lugar de NULL cuando LAG() intente obtener valores de filas más allá de las que existen en nuestro conjunto de datos. Tanto para LAG() como para LEAD(), esto se hace especificando un tercer argumento, el valor predeterminado. Recuerda que el argumento desplazamiento es necesario para especificar el argumento del valor por defecto; aquí, especificamos un desplazamiento de 1 para buscar en la fila de arriba. A continuación, especificamos 0 como tercer argumento. Esto pone a cero cualquier intento de obtener valores de filas que no existen, como es el caso aquí para la primera fila (no hay ninguna fila por encima de la primera fila).

Observa que el valor predeterminado cero se asigna sólo a las filas que no existen; las filas adyacentes por encima que sí existen pero con NULLs en cantidad_actual se dejan sólo como NULL en lugar de cambiarlas a 0. Puedes ver esto en la fila donde mes=4: aunque cuenta_actual para la fila por encima (mes=3) es NULL, no se reemplaza con un cero, ya que la fila anterior sí existe y sólo ocurre que contiene un NULL en cantidad_actual.

Uso de LAG() y LEAD() con particiones

Sigamos con el mismo ejemplo, pero ahora examinemos un caso en el que necesitamos PARTITION BY en la cláusula OVER. A continuación, se muestra la siguiente parte de la tabla venta_producto con otro producto cuyo ID=2.

id_de_productomescantidad
11125
12135
13NULL
1490
21150
22100
23185
24190

La siguiente consulta:

SELECT id_de_producto, mes,
  LAG(cantidad,1,0) OVER(PARTITION BY id_de_producto ORDER BY mes) AS cantidad_anterior,
  cantidad AS cantidad_actual,
  cantidad - LAG(cantidad,1,0) OVER(PARTITION BY id_de_producto ORDER BY mes) AS diferencia
FROM venta_producto;

Devuelve el siguiente resultado:

id_de_productomescantidad_anteriorcantidad_actualdiferencia
110125125
1212513510
13135NULLNULL
14NULL90NULL
210150150
22150100-50
2310018585
241851905

Tenemos varios productos en esta tabla. Para calcular las diferencias entre la cantidad de ventas actuales y anteriores por separado para cada producto, especificamos PARTITION BY antes de ORDER BY en la cláusula OVER.

Puedes nombrar una columna o una lista de columnas en PARTITION BY. Aquí, utilizamos la columna id_de_producto para dividir los registros en particiones y luego ordenar por mes dentro de cada partición. Como resultado, cada partición comienza con el mes 1 y termina con el mes 4.

PARTITION BY es similar a GROUP BY en el sentido de que agrupa los mismos valores. Sin embargo, a diferencia de GROUP BY, PARTITION BY no contrae las filas originales en una sola fila; las filas originales siguen siendo accesibles. Puedes leer más sobre la diferencia entre PARTITION BY y ORDER BY en el artículo "¿Cuál es la diferencia entre GROUP BY y PARTITION BY?".

¡Las funciones LAG y LEAD son muy útiles!

Las funciones posicionales como LAG() y LEAD() son útiles en muchas situaciones. Suelen utilizarse en la creación de informes, porque pueden referirse a las filas de arriba o de abajo, como hemos visto en estos ejemplos. Espero que este artículo te ayude a ampliar tus conocimientos de SQL sobre las funciones de ventana. Lee más sobre las funciones posicionales en los artículos "Funciones de ventana comunes en SQL: Funciones posicionales", de Aldo Zelen y "¿Cuándo se utilizan las Funciones de ventana en SQL?", de Tihomir Babic. Si te interesa aprender más sobre las funciones de ventana, prueba nuestro curso interactivo "Funciones de ventana" en la plataforma LearnSQL.es.