14th Jul 2022 Lectura de 9 minutos Cómo calcular la diferencia entre dos filas de SQL Ignacio L. Bisso SQL aprender SQL funciones de ventana Índice Encontrar la diferencia entre dos valores de la misma fila Cómo calcular la diferencia de dos valores de la misma columna Cómo calcular la diferencia entre valores de fecha en SQL Cómo encontrar la diferencia entre registros no consecutivos Más información sobre los cálculos en SQL y las funciones de ventana Calcular la diferencia entre dos filas de SQL puede ser una tarea difícil. Pero, es posible, y hay más de una manera de hacerlo. En este artículo, explicaré cómo utilizar las funciones de ventana de SQL LEAD() y LAG() para encontrar la diferencia entre dos filas de una tabla. Me gusta pensar que este artículo es como una "hora feliz" dos por uno; se puede aprender sobre dos temas (calcular la diferencia entre dos filas y las funciones de ventana de SQL), leyendo solo un artículo. Ahora, ¡entremos de lleno en el tema! Si quiere aprender sobre las funciones de ventana, consulte nuestro curso interactivo Funciones de ventana. Si ya las conoce y quiere practicar la escritura de consultas de funciones de ventana, le recomiendo nuestra página Ejercicios prácticos de funciones de ventana, que tiene 100 ejercicios prácticos. Encontrar la diferencia entre dos valores de la misma fila Para calcular cualquier diferencia, hacen falta dos elementos; para calcular una diferencia en SQL, hacen falta dos registros. También se puede calcular la diferencia entre dos columnas del mismo registro, como mostraré más tarde. Es muy fácil. Sin embargo, me centraré principalmente en encontrar la diferencia entre dos valores de la misma columna de registros diferentes. Primero, voy a explicar un poco sobre nuestros datos. Utilizaremos una base de datos con dos tablas, como las que utiliza el Gobierno de una provincia imaginaria para definir algunos programas sociales. La primera tabla es housing, que contiene datos sobre el número de personas que alquilan, poseen o necesitan una vivienda. Es la siguiente: Tabla housing CityYearTotal PopulationPopulation Owning housePopulation renting housePopulation needing house Goldpolis201722501500500250 Silverpolis201717501200400150 Bronzepolis201714201000300120 Goldpolis201824251600550275 Silverpolis201819201300410210 Bronzepolis201817301020300410 Goldpolis201926101750580280 Silverpolis201921101400420290 Bronzepolis201920101050300660 Para diseñar un plan de construcción de viviendas para la gente que las necesita, el Gobierno quiere obtener algunas métricas sobre los problemas de vivienda de diferentes ciudades. Supongamos que el Gobierno quiere saber cuántas personas de cada ciudad no tienen casa. La consulta será la siguiente: SELECT city, total_population, total_population - population_owning_house AS people_not_owning_house FROM housing En esta consulta, está claro que se está calculando una diferencia, utilizando dos columnas diferentes del mismo registro. A continuación, calcularemos las diferencias, utilizando dos registros. Cómo calcular la diferencia de dos valores de la misma columna Normalmente, todas las operaciones que realizamos en una consulta SQL están relacionadas con un registro. Pero, en este caso, necesitamos otro registro diferente. Esta es la parte complicada. Utilizaremos una técnica que emplea las funciones de ventana LAG() y LEAD() para obtener datos de otro registro. Si quiere profundizar en el tema, le sugiero que lea este artículo sobre las funciones de ventana, que explica claramente las funciones de ventana con multitud de ejemplos. Supongamos que, para una ciudad específica ("Bronzepolis"), se quiere obtener la variación en el número de personas que necesitan una vivienda en relación al año anterior. Esta sería la consulta: SELECT city, year, population_needing_house, LAG(population_needing_house) AS previous_year, population_needing_house - LAG(population_needing_house) OVER (ORDER BY year ) AS difference_previous_year FROM housing WHERE city = ‘Bronzepolis’ ORDER BY year En el texto azul, puede ver el cálculo del delta de SQL entre dos filas. Para calcular una diferencia, se necesita un par de registros. Esos dos registros son "el registro actual" y "el registro del año anterior". Ese registro se obtiene con la función de ventana LAG(). Con esa función, se pueden obtener los datos del registro anterior (en base a un criterio de orden, que aquí es "ORDER BY year"). A continuación, se muestra el resultado de esta consulta. Las flechas rojas muestran que el valor de la función LAG() devuelve el mismo valor de population_needing_house que el registro del año anterior. La columna de la derecha muestra el resultado de la diferencia entre ese año y el anterior. Para la siguiente consulta, ampliaremos el ámbito del análisis de los problemas de vivienda a todas las ciudades. Queremos la diferencia entre un año y el anterior de la columna population_needing_house para cada ciudad. En primer lugar, eliminaremos la condición city = ‘Bronzepolis’. Queremos calcular los valores para cada ciudad, por lo que necesitamos una forma de separar los datos en grupos. Por eso, añadimos la cláusula PARTITION BY city a LAG(). PARTITION BY city le permite procesar todos los registros de la misma ciudad en la misma ventana. Volverá a utilizar LAG() para calcular la diferencia entre el número de personas que necesitan una vivienda entre este año y el anterior. Veamos la consulta: SELECT city, year, population_needing_house, LAG(population_needing_house) OVER (PARTITION BY city ORDER BY year ) AS previous_year, population_needing_house - LAG(population_needing_house) OVER (PARTITION BY city ORDER BY year ) AS difference_previous_year FROM housing ORDER BY city, year En el texto azul se puede ver cómo se calcula la diferencia. Esta es una versión en español de lo que ocurre: difference_previous_year = population_needing_house del registro actual - population_needing_house del registro del año anterior Donde: Population_needing_house del registro actual es la columna population_needing_house y Population_needing_house del registro del año anterior se obtiene a través de la función LAG(population_needing_house) OVER (PARTITION BY city ORDER BY year ) CityYearPopulation needing housePrevious YearDifference previous year Bronzepolis2017150nullnull Bronzepolis2018410150290 Bronzepolis2019660410250 Goldpolis2017250nullnull Goldpolis201827525025 Goldpolis20192802755 Silverpolis2017150nullnull Silverpolis201821015060 Silverpolis201929021080 Por lo que, se utiliza la cláusula PARTITION para crear un conjunto con todos los registros de la misma ciudad. A continuación, se utiliza la cláusula ORDER BY para ordenar todos estos registros según su año. Por último, se utiliza la función LAG() para obtener el valor de population_needing_house del registro anterior. LEAD() es otra función de ventana de SQL, que es similar a LAG(). Sin embargo, devuelve el siguiente registro del conjunto (en nuestro ejemplo, sería el registro del año siguiente). Si echa un vistazo a las dos consultas anteriores, verá que utilizamos el mismo patrón para calcular la diferencia: utilizar LAG() para restar el valor anterior de la columna del valor actual (o utilizar LEAD() para restar el siguiente registro). Las funciones de ventana de SQL son muy potentes. Para ver ejemplos de diferentes áreas de negocio, como finanzas, ventas y comercio, consulte este artículo sobre cuándo utilizar las funciones de ventana de SQL. Cómo calcular la diferencia entre valores de fecha en SQL En los ejemplos anteriores, calculamos el delta de dos filas, utilizando valores numéricos de columnas. Ahora, demostraré cómo calcular la diferencia entre dos valores del tipo de datos fecha. Primero, pensemos sobre el tipo de datos del resultado. Cuando se calcula la diferencia entre dos valores de fechas, el resultado no es una fecha. Es un intervalo que representa el número de días que hay entre las dos fechas. Supongamos que existe una tabla llamada hospital_statistics que almacena las estadísticas de los tres hospitales de la provincia. A continuación, se muestra un ejemplo de los datos de esa tabla: Tabla hospital_statistics Hospital namedayillnessnumber of patients Hospital of Bronzepolis2017-03-22MDLR1 Hospital of Goldpolis2017-12-03MDLR1 Hospital of Silverpolis2018-08-03MDLR1 Hospital of Bronzepolis2019-01-23MDLR1 Hospital of Goldpolis2019-06-14MDLR1 Supongamos que existe una enfermedad rara llamada MDLR. El Gobierno quiere estudiar la frecuencia con la que los pacientes con MDLR ingresan en alguno de los hospitales, por lo que, pidió un informe que incluya las columnas day, hospital name, number of cases y days_since_the_last_case. Utilizaremos la siguiente consulta SQL para crear el informe: SELECT day, hospital_name, number_of_patients, day - LAG(day) OVER (ORDER BY day) AS days_since_last_case FROM hospital_statistics WHERE illness_name = 'MDLR' ORDER BY day Se puede ver que es el mismo patrón que usamos antes. Ahora, lo estamos usando para calcular los días transcurridos desde el último caso. Lo único que cambia es que estamos calculando una diferencia entre dos fechas, en lugar de entre valores numéricos. Como se puede ver en los resultados, el valor de la columna days_since_last_case es un número entero, que representa el número de días. DayHospital NameIllnessPatientsdays_since_last_case 2017-03-22Hospital of BronzepolisMDLR1null 2017-12-03Hospital of GoldpolisMDLR1256 2018-08-03Hospital of SilverpolisMDLR1243 2019-01-23Hospital of BronzepolisMDLR1173 2019-06-14Hospital of GoldpolisMDLR1142 SQL también permite calcular diferencias entre valores tipo timestamp. También, hay otras operaciones aritméticas interesantes con las fechas que se pueden utilizar en tipos de datos relacionados con fechas. Si quiere profundizar más en el tema, le sugiero el artículo Cómo utilizar funciones de ventana de SQL para analizar datos de series temporales sobre COVID-19. Cómo encontrar la diferencia entre registros no consecutivos Hasta ahora, hemos calculado las diferencias entre registros contiguos basándonos en criterios de orden específicos. En algunos casos, necesitará calcular la diferencia entre registros no contiguos. Como ejemplo, volvamos a la primera consulta. Supongamos que queremos añadir otra columna que muestre el número de casos en los dos últimos años. Afortunadamente, LAG() y LEAD() tienen un parámetro opcional que especifica cuántos registros se saltarán antes/después del registro actual. Por defecto, este parámetro es 1 (es decir, "utilizar el registro siguiente/anterior"), pero se puede establecer otro número. Así, con este nuevo parámetro, la consulta será: SELECT city, year, population_needing_house, LAG(population_needing_house) OVER (PARTITION BY city ORDER BY year ) AS one_year_before, LAG(population_needing_house,2) OVER (PARTITION BY city ORDER BY year ) AS two_years_before, population_needing_house - LAG(population_needing_house) OVER (PARTITION BY city ORDER BY year ) AS difference_previous_year, population_needing_house - LAG(population_needing_house,2) OVER (PARTITION BY city ORDER BY year ) AS difference_last_two_years FROM housing ORDER BY 1, 2 DESC El cálculo de la diferencia de dos registros no consecutivos está marcado en azul. En la siguiente imagen, podemos ver la nueva columna Difference last two years solo para los valores de 2019. Esto se debe a que 2019 es el único año para el que existen datos de dos años anteriores. Las líneas rojas conectan los resultados de la función LAG() (obteniendo los datos de 2017 y mostrando los mismos datos en el registro de 2017). Como se puede ver, las dos líneas tienen el mismo valor. En este artículo se mostró la importancia de LAG() y LEAD(), pero hay muchas más funciones de ventana en SQL. Si quiere conocer más sobre ellas, lea este artículo sobre las funciones de ventana. Más información sobre los cálculos en SQL y las funciones de ventana Ya conocemos cómo utilizar SQL para calcular la diferencia entre filas consecutivas y cómo usar LAG() y LEAD() para encontrar la diferencia entre filas no consecutivas. Aunque hay otras formas de calcular esta diferencia, como, por ejemplo, a través de una autocombinación, estos métodos son muy útiles. Si va a utilizar las funciones de ventana (o, de hecho, SQL) con frecuencia, o si simplemente quiere mejorar sus conocimientos, esta completa hoja de referencia de las funciones de ventana le ayudará enormemente. Para aprender las funciones de ventana a través de ejercicios, pruebe nuestro curso Funciones de ventana. En este artículo encontrará más información sobre el curso. Tags: SQL aprender SQL funciones de ventana