7th Jul 2022 Lectura de 9 minutos ¿Qué es la cláusula OVER de MySQL? Ignacio L. Bisso SQL aprender SQL funciones de ventana Índice Funciones de ventana: Una función muy solicitada Cómo funciona un marco de ventana deslizante Aprendiendo la Cláusula OVER de MySQL con un ejemplo Uso de Funciones Posicionales en Ventanas Ordenadas Más sobre MySQL OVER y Funciones de ventana Si quiere aprender las funciones de ventana en MySQL, necesita entender la cláusula OVER. En este artículo, utilizamos ejemplos del mundo real para explicar qué es la cláusula OVER de MySQL, cómo funciona y por qué es tan impresionante. En 2018, MySQL introdujo una nueva característica: las funciones de ventana, a las que se accede a través de la cláusula OVER. Las funciones de ventana son un recurso súper potente disponible en casi todas las bases de datos SQL. Realizan un cálculo específico (por ejemplo, suma, recuento, promedio, etc.) en un conjunto de filas; este conjunto de filas se llama "ventana" y se define mediante la cláusula MySQL OVER. En este artículo, explicaremos cómo utilizar la cláusula OVER de MySQL en diferentes escenarios. También le presentaremos varias funciones de ventana. Espero que, después de leer este artículo, te convenzas de que vale la pena aprender las funciones de ventana. ¡También conocerás los fundamentos de cómo aplicarlas en tus consultas! Funciones de ventana: Una función muy solicitada Las funciones de ventana han estado disponibles en la mayoría de las principales bases de datos desde hace bastante tiempo, pero hasta 2018 no estaban disponibles en MySQL. Para mantener MySQL al día, las funciones de ventana se introdujeron en MySQL 8.02. Si planeas trabajar con la versión 8 de MySQL, vale la pena aprender las funciones de ventana y la cláusula OVER, ya que son muy potentes. ¿Cuándo utilizaría las funciones ventana? Hay muchas ocasiones en las que resultan útiles, por ejemplo, para calcular el salario medio de un determinado grupo de empleados. En este caso, la definición del grupo es el punto central; no quieres la media de los salarios de todos los empleados, y si te equivocas de grupo el resultado será erróneo. La definición de un grupo de registros es la razón de ser de la cláusula OVER: dicta dónde trabajará la función ventana. A lo largo de este artículo, crearemos algunos ejemplos de consulta basados en una base de datos que contiene registros de un grupo de agricultores que producen naranjas. Los agricultores comparten sus datos de producción, que se almacenan en la tabla orange_production tabla que se ve a continuación: farmer_nameorange_varietycrop_yearnumber_of_treeskilos_producedyear_rainkilo_price PierreGolden20152400825004001.21 PierreGolden20162400510001801.35 OlekGolden20174000780002501.42 SimonSuperSun20173500750002501.05 PierreGolden20172400625002501.42 OlekGolden20184100690001501.48 SimonSuperSun20183500740001501.07 PierreGolden20182450645002001.43 El caso de uso más sencillo es una cláusula OVER vacía; esto significa que la ventana de registros es el conjunto completo de registros devueltos por la consulta. Por ejemplo, si nuestros agricultores quieren tener un informe de cada registro de agricultores junto con el total de la producción de naranjas en 2017, escribiríamos esta consulta: SELECT farmer_name, kilos_produced, SUM(kilos_produced) OVER() total_produced FROM orange_production WHERE crop_year = 2017 Aquí, la cláusula OVER construye una ventana que incluye todos los registros devueltos por la consulta, es decir, todos los registros del año 2017. El resultado es: farmer_namekilos_producedtotal_produced Olek78000215500 Simon75000215500 Pierre62500215500 Cómo funciona un marco de ventana deslizante Ese fue un ejemplo muy simple de la cláusula MySQL OVER. La ventana de registros era estática (la ventana era la misma para todas las filas devueltas por la consulta). Sin embargo, uno de los puntos fuertes de la cláusula OVER es poder crear una ventana dinámica de registros (también llamada marco de ventana deslizante). Los marcos de ventana deslizantes o dinámicos significan que la ventana de registros puede ser diferente para cada fila devuelta por la consulta. Además, la ventana se crea en función de la fila actual de la consulta, por lo que las filas de la ventana pueden cambiar cuando cambia la fila actual. Veamos un ejemplo de ventana deslizante. Supongamos que nuestros agricultores quieren ver su propia producción junto con la producción total de la misma variedad de naranja. SELECT farmer_name, orange_variety, crop_year, kilos_produced, SUM(kilos_produced) OVER(PARTITION BY orange_variety) AS total_same_variety FROM orange_production La cláusula OVER(PARTITION BY orange_variety) crea ventanas agrupando todos los registros con el mismo valor en la columna orange_variety. Esto nos da dos ventanas: 'Golden' y 'SuperSun'. En la tabla siguiente, cada ventana se muestra con un color diferente: farmer_nameorange_varietycrop_yearnumber_of_treeskilos_producedyear_rainkilo_ price PierreGolden20152400825004001.21 PierreGolden20162400510001801.35 OlekGolden20174000780002501.42 PierreGolden20172400625002501.42 OlekGolden20184100690001501.48 PierreGolden20182450645002001.43 SimonSuperSun20173500750002501.05 SimonSuperSun20183500740001501.07 Ahora puede ver el resultado de la consulta: farmer_nameorange_varietycrop_yearkilos_producedtotal_same_variety PierreGolden201582500407500 PierreGolden201651000407500 OlekGolden201778000407500 PierreGolden201762500407500 OlekGolden201869000407500 PierreGolden201864500407500 SimonSuperSun201775000149000 SimonSuperSun201874000149000 Observe que la columna Total Same Variety (en el extremo derecho) incluye la producción de todos los años. Quizá cada agricultor prefiera comparar su producción con la producción total de la misma variedad en el mismo año. Esta comparación les permite ver su parte de la tasa de producción. Para ello, tenemos que añadir la columna crop_year a la cláusula PARTITION BY. La consulta será la siguiente: SELECT farmer, orange_variety, crop_year, kilos_produced, SUM(kilos_produced) OVER(PARTITION BY orange_variety, crop_year) AS total_same_variety_year FROM orange_production La cláusula OVER(PARTITION BY orange_variety, crop_year) crea ventanas agrupando todos los registros con el mismo valor en las columnas orange_variety y crop_year. A continuación, hemos vuelto a utilizar diferentes colores para mostrar las ventanas de filas creadas por esta cláusula OVER: farmer_nameorange_varietycrop_yearnumber_of_treeskilos_producedyear_rainkilo_price PierreGolden20152400825004001.21 PierreGolden20162400510001801.35 OlekGolden20174000780002501.42 PierreGolden20172400625002501.42 OlekGolden20184100690001501.48 PierreGolden20182450645002001.43 SimonSuperSun20173500750002501.05 SimonSuperSun20183500740001501.07 Y los resultados de la consulta son: farmer_nameorange_varietycrop_yearkilos_producedtotal_same_variety_year PierreGolden20158250082500 PierreGolden20165100051000 OlekGolden201778000140500 PierreGolden201762500140500 OlekGolden201869000133500 PierreGolden201864500133500 SimonSuperSun20177500075000 SimonSuperSun20187400074000 Si estás interesado en profundizar en las funciones ventana de MySQL, te sugiero el curso LearnSQL.es Funciones de ventana, donde puedes encontrar una descripción completa de este tema y varios ejemplos. Si vas a utilizar las funciones ventana con frecuencia, esta hoja de trucos - una guía rápida súper completa de las funciones ventana - es muy útil. Pero prosigamos con nuestra propia exploración de OVER y las funciones ventana en MySQL primero. Aprendiendo la Cláusula OVER de MySQL con un ejemplo En esta sección, exploraremos varias consultas de ejemplo que muestran diferentes usos de la cláusula OVER en MySQL. En primer lugar, utilizaremos la subcláusula ORDER BY en la cláusula OVER. ORDER BY generará una ventana con los registros ordenados por un criterio definido. Algunas funciones (como SUM(), LAG(), LEAD() y NTH_VALUE()) pueden devolver diferentes resultados dependiendo del orden de las filas dentro de la ventana. Supongamos que el agricultor Pierre quiere conocer su producción acumulada a lo largo de los años: SELECT farmer, crop_year, kilos_produced, SUM(kilos_produced) OVER(ORDER BY crop_year) cumulative_previous_years FROM orange_production WHERE farmer = ‘Pierre’ La función de ventana SUM(kilos_produced) OVER(ORDER BY crop_year) trabaja sobre una ventana ordenada. Y sólo tiene en cuenta las filas actuales y anteriores (es decir, los valores actuales y anteriores de crop_year ). Podemos ver el resultado de este acumulado SUM() en la tabla de resultados: farmer_namecrop_yearkilos_producedcumulative_previous_years Pierre20158250082500 Pierre201651000133500 Pierre201762500196000 Pierre201864500260500 En el siguiente ejemplo, combinaremos dos subcláusulas (PARTITION BY y ORDER BY) en la cláusula OVER. Supongamos que los agricultores quieren un informe que muestre el total producido por cada agricultor cada año y el total de los años anteriores. Entonces tenemos que particionar por la columna farmer y ordenar por crop_year: SELECT farmer, crop_year, kilos_produced, SUM(kilos_produced) OVER(PARTITION BY farmer ORDER BY crop_year) cumulative_kilos_produced FROM orange_production La siguiente imagen muestra las ventanas particionadas por farmer_name en diferentes colores; observe que dentro de cada ventana, las filas están ordenadas por crop_year. farmer_nameorange_varietycrop_yearnumber_of_treeskilos_ producedyear_rainkilo_price PierreGolden20152400825004001.21 PierreGolden20162400510001801.35 PierreGolden20172400625002501.42 PierreGolden20182450645002001.43 SimonSuperSun20173500750002501.05 SimonSuperSun20183500740001501.07 OlekGolden20174000780002501.42 OlekGolden20184100690001501.48 La expresión SUM(kilos_produced) OVER(PARTITION BY farmer ORDER BY crop_year) ordena las filas en la partición (que se basa en el valor farmer ) utilizando los valores de crop_year. Puede ver esto en la tabla de resultados: farmer_ namecrop_ yearkilos_ producedcumulative_ previous_years Olek20177800078000 Olek201869000147000 Pierre20158250082500 Pierre201651000133500 Pierre201762500196000 Pierre201864500260500 Simon20177500075000 Simon201874000149000 Para más información sobre la combinación de las cláusulas PARTITION BY y ORDER BY, consulte el artículo SQL Funciones de ventana por explicación. Uso de Funciones Posicionales en Ventanas Ordenadas Así que, ahora puede ver la importancia de poder ordenar las filas dentro de una ventana. De hecho, algunas funciones de ventana de MySQL sólo funcionan en ventanas ordenadas. Por ejemplo, la función LAG() nos permite obtener un valor de columna de la fila anterior (relacionada con la fila actual) en una ventana ordenada. Digamos que queremos un informe que muestre la producción del año anterior comparada con la producción del año actual. Para ello, utilizamos la función LAG() en una ventana ordenada por crop_year: SELECT farmer, crop_year, kilos_produced AS current_year_production, LAG(kilos_produced) OVER(PARTITION BY farmer ORDER BY crop_year)AS previous_year_production FROM orange_production La función LAG() puede devolver cualquier valor de columna de la fila anterior a la actual, como muestra el siguiente resultado de la consulta: farmer_namecrop_yearkilos_producedprevious_year_production Olek201778000NULL Olek20186900078000 Pierre201582500NULL Pierre20165100082500 Pierre20176250051000 Pierre20186450062500 Simon201775000NULL Simon20187400075000 La función LEAD() devuelve cualquier valor de columna de la fila posterior a la fila actual. Además, la función NTH_VALUE() devuelve la fila en cualquier posición especificada en una ventana ordenada (por ejemplo, primera, segunda, última). Estas funciones de ventana de MySQL le ayudan a crear fácilmente informes complejos. Probemos una operación matemática utilizando las funciones de ventana de MySQL. Supongamos que los agricultores quieren un informe con el delta de producción relacionado con el año anterior. Podemos utilizar la función LAG() para calcular la diferencia entre las producciones del año anterior y del actual: SELECT farmer, crop_year, kilos_produced current_year_production, kilos_produced - LAG(kilos_produced) OVER(PARTITION BY farmer ORDER BY crop_year) AS production_delta FROM orange_production La expresión kilos_produced - LAG(kilos_produced) OVER(PARTITION BY farmer ORDER BY crop_year) calcula el delta de producción entre el año anterior y el actual, como podemos ver en los resultados: farmer_namecrop_yearkilos_producedproduction_ delta Olek201778000NULL Olek201869000-9000 Pierre201582500NULL Pierre201651000-31500 Pierre20176250011500 Pierre2018645002000 Simon201775000NULL Simon201874000-1000 Para aquellos lectores que quieran profundizar en las funciones posicionales, sugiero el artículo Funciones de ventana comunes de SQL: Funciones Posicionales, que tiene varios ejemplos de este interesante tipo de función de ventana. Más sobre MySQL OVER y Funciones de ventana En este artículo, cubrimos varios ejemplos de uso de la cláusula OVER de MySQL, desde usos muy simples hasta bastante complejos. Saber cómo funciona OVER y qué filas incluye en la ventana es fundamental para utilizar las funciones de ventana. Hay muchas funciones de ventana de MySQL con las que puede experimentar: AVG(), MIN(), MAX(), LAG(), LEAD() y NTH_VALUE(). Todas ellas utilizan la cláusula OVER de la misma manera que acabamos de explicar. Finalmente, para aquellos lectores que quieran aprender más sobre las funciones ventana de MySQL, recomiendo el curso interactivo LearnSQL Funciones de ventana. Puedes leer más sobre él en nuestro post Curso SQL del Mes - Funciones de ventana. En el curso encontrarás explicaciones detalladas y muchos ejemplos de uso de diferentes funciones de ventana. Y recuerde: ¡cuando aumenta sus conocimientos de MySQL, aumenta su patrimonio! Tags: SQL aprender SQL funciones de ventana