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

¿Qué son las funciones de ventana SQL?

¿Necesita mejorar su análisis de datos? Aprenda aquí estas funciones de ventana SQL y llevará sus habilidades de análisis al siguiente nivel. Incluye ejercicios prácticos y explicaciones detalladas.

La primera vez que oí hablar de las funciones de ventana de SQL, pensé que se trataba de una extraña unión entre SQL y Windows. Me equivocaba. Las funciones de ventana de SQL no tienen nada que ver con ese famoso sistema operativo. Son funciones SQL que realizan cálculos sobre el conjunto de filas relacionadas con la fila actual. Este conjunto de filas se denomina ventana o marco de ventana, de ahí el nombre de la función.

Es posible que también oigas hablar de funciones de ventana en SQL, funciones analíticas o las funciones OVER(). Todos ellos no son más que nombres alternativos para las funciones de ventana de SQL, un conjunto de herramientas extremadamente útiles para el análisis de datos.

En este artículo, le mostraremos qué puede hacer con las funciones de ventana y cómo. Empezaré con una breve historia de las funciones ventana de SQL y explicaré por qué se llaman así. A continuación, te guiaré a través de la sintaxis y te mostraré cómo funciona con varios ejemplos. Después de practicar la sintaxis, estaremos listos para ejemplos reales de funciones ventana de la vida de un analista de datos. Y aquí viene lo más jugoso: después de cada ejemplo, hay un ejercicio para que lo resuelvas y aprendas codificando.

Sin embargo, la principal fuente de tus conocimientos sobre este tema debe ser nuestro Funciones de ventana curso. Sus 218 ejercicios interactivos cubren en detalle las funciones de la ventana SQL. En otras palabras, aprenderá sobre los marcos de ventana y las cláusulas OVER(), PARTITION BY y ORDER BY. Todo esto es necesario para agregar, clasificar y analizar datos utilizando funciones ventana.

Breve historia de SQL Funciones de ventana

Las funciones ventana se introdujeron por primera vez en la Base de Datos Oracle8i, que se lanzó en 1998. Sin embargo, se incluyeron en el estándar SQL cinco años después con SQL:2003.

Posteriormente, Microsoft las incluyó en SQL Server 2005. Otros sistemas de gestión de bases de datos (DBMS) los siguieron; PostgreSQL los ha soportado desde que PostgreSQL 8.4 fue lanzado en 2009; MariaDB los incluyó con la versión 10.2 (2016), y MySQL los agregó a la versión 8 en 2018.

Las funciones de ventana son una característica bastante nueva en SQL. Debido a eso, no forman parte del plan de estudios habitual de SQL. Al aprenderlas, estarás por delante en comparación con muchos usuarios de SQL.

¿Qué es una ventana?

Un conjunto de filas relacionadas con la fila actual se denomina ventana o marco de ventana. De ahí el nombre de estas funciones: su resultado se basa en un marco de ventana deslizante.

Por ejemplo, puede calcular una suma acumulada como se muestra a continuación:

datesalescumulative_sum
2023-10-014,2414,241
2023-10-022,3896,630
2023-10-031,5808,210
2023-10-043,39511,605
2023-10-051,26512,870

La ventana para la suma acumulada 2023-10-04 está resaltada en verde. Incluye la fila actual (para 2023-10-04) y todas las filas anteriores. Por lo tanto, la suma acumulada se calcula como la suma de todas las ventas anteriores y actuales: 4.241 + 2.389 + 1.580 + 3.395 = 11.605. (Observe que la fila resaltada en puntos rojos no está incluida en la ventana ni en la suma).

Cuando pasamos a la fila siguiente, la ventana también se desplaza: ahora incluirá todas las filas anteriores (en verde) y la fila actual (en puntos rojos). Ahora la suma acumulada es 4.241 + 2.389 + 1.580 + 3.395 + 1.265 = 12.870.

Así pues, la ventana es el conjunto de filas relacionadas con la fila actual que se utilizan en los cálculos para esta fila. La ventana cambia (se desliza) a medida que nos desplazamos por las filas; gracias a estas imágenes de una ventana que se desliza, obtenemos el nombre de estas funciones.

Sintaxis de las funciones ventana de SQL

La sintaxis de las funciones ventana es:

SELECT column_1,
       column_2,
	 <window_function> OVER(PARTITION BY … ORDER BY … ) AS column_alias
FROM table;

Esto es lo que hace cada parte

  • <window_function> - Especifica la función a aplicar a esa ventana.
  • OVER() - Define la ventana (conjunto de filas) e indica que se trata de una función ventana; sin esta cláusula, no es una función ventana.
  • <window_frame> - Define el tamaño del marco de la ventana (opcional).
  • PARTITION BY - Divide la ventana en grupos más pequeños llamados particiones (opcional); si se omite, todo el conjunto de resultados es una partición.
  • ORDENAR POR - Ordena las filas dentro del marco de la ventana (opcional), es decir, decide en qué orden se realizará la operación de ventana; si se omite, el orden de las filas dentro de la partición es arbitrario.

Las cláusulas adicionales pueden definir aún más la ventana. Su sintaxis es la siguiente

[<ROWS or RANGE clause> BETWEEN <lower_bound> AND <upper_bound>]

La cláusula ROWS define la ventana en términos del número fijo de filas en relación con la fila actual.

La cláusula RANGE hace lo mismo. Pero también tiene en cuenta todas las filas con los mismos valores en las columnas especificadas en la cláusula ORDER BY que la fila actual.

Los límites de la ventana pueden definirse como

  • UNBOUNDED PRECEDING - Todas las filas anteriores a la fila actual.
  • n PRECEDING - Un número definido de filas antes de la fila actual.
  • CURRENT ROW - Incluye la fila actual.
  • n FOLLOWING - Un número definido de filas después de la fila actual.
  • UNBOUNDED FOLLOWING - Todas las filas después de la fila actual.

Veamos cómo funciona en la práctica.

Ejemplos de conjuntos de datos y sintaxis

Utilizaremos la tabla album_catalogue en todos estos ejemplos. Puede crearla usted mismo utilizando este script. A continuación se muestra una instantánea de los datos:

idalbum_titlealbum_lengthalbum_genreartistcopies_soldsales_period
1Wednesday Morning, 3 A.M0:31:38FolkSimon & Garfunkel10432022_1Q
2EnRoute: John Scofield Trio LIVE1:13:48JazzJohn Scofield Trio5122022_1Q
3Nasty Gal0:39:15FunkBetty Davis8092022_1Q
4The New Folk Sound of Terry Callier0:37:41FolkTerry Callier9032022_1Q
5In a Silent Way0:38:08JazzMiles Davis4282022_1Q

El conjunto de datos es una lista de álbumes con su duración, género, artista y datos de ventas, incluyendo el número de copias vendidas y el periodo (trimestres). Los datos llegan hasta el tercer trimestre de 2023.

Primero te mostraré varios ejemplos, explicando cada parte crucial de la sintaxis de las funciones de ventana en el camino.

Sintaxis Ejemplo #1: OVER ()

Puede utilizar la función de ventana SUM() sólo con la cláusula OVER() para obtener las ventas totales en el cuarto trimestre de 2022:

SELECT sales_period,
 album_title,
	 artist,
	 copies_sold,
	 SUM (copies_sold) OVER() AS sold_in_4Q_2022
FROM album_catalogue
WHERE sales_period = '2022_4Q';

Quiero la suma de las copias vendidas, así que especifico esta columna en SUM(). La cláusula OVER() es obligatoria. Si desea utilizar OVER() sin ninguna de las cláusulas opcionales, simplemente deje los paréntesis vacíos.

Utilizo WHERE para obtener sólo los datos del trimestre deseado.

Cuando se escribe una consulta como ésta - con un OVER() vacío - todo el conjunto de resultados (columnas seleccionadas, filtros aplicados, etc.) se tiene en cuenta al realizar los cálculos de la función ventana. Aquí, el resultado muestra las ventas individuales de cada álbum vendido en el cuarto trimestre de 2022. También muestra las ventas totales de todos los álbumes vendidos en ese periodo.

sales_periodalbum_titleartistcopies_soldsold_in_4q_2022
2022_4QWednesday Morning, 3 A.MSimon & Garfunkel8097,403
2022_4QEnRoute: John Scofield Trio LIVEJohn Scofield Trio6127,403
2022_4QNasty GalBetty Davis3697,403
2022_4QThe New Folk Sound of Terry CallierTerry Callier2147,403
2022_4QIn a Silent WayMiles Davis657,403
2022_4QCold SweatJames Brown2097,403
2022_4QThe Freewheelin' Bob DylanBob Dylan2467,403
2022_4QMy Favorite ThingsJohn Coltrane3777,403
2022_4QA Whole New ThingSly and the Family Stone8167,403
2022_4QFive Leaves LeftNick Drake4007,403
2022_4QHead HuntersHerbie Hancock4097,403
2022_4QIn the Right PlaceDr. John9127,403
2022_4QBlueJoni Mitchell4127,403
2022_4QConciertoJim Hall6127,403
2022_4QDirty MindPrince9417,403

Con la ayuda de SUM() y OVER(), puedo mostrar las ventas individuales de cada álbum y el total trimestral.

Ejemplo sintáctico nº 2: OVER (ORDER BY)

Puede añadir cláusulas adicionales dentro de la cláusula OVER() para cambiar la definición del marco de la ventana. Una de estas cláusulas es ORDER BY. La cláusula ORDER BY define la ordenación de las filas dentro de un marco de ventana: las filas pueden ser procesadas por la función ventana en un orden determinado.

Veamos un ejemplo. Puede calcular la suma acumulada añadiendo ORDER BY a la consulta anterior. En este ejemplo, quiero ver cómo se vende el álbum 'In the Right Place' a lo largo del tiempo y el número acumulado de álbumes vendidos hasta un periodo de tiempo determinado. Esta es la consulta:

SELECT sales_period,
	 album_title,
	 artist,
	 copies_sold,
	 SUM (copies_sold) OVER(ORDER BY sales_period ASC) AS cumulative_sum
FROM album_catalogue
WHERE album_title = 'In the Right Place';

La misma columna copies_sold está en SUM(). Esta vez, OVER() contiene la cláusula ORDER BY. Quiere mostrar las ventas acumuladas desde el primer trimestre hasta el último. Por eso necesita sales_period y ASC en ORDER BY.

sales_periodalbum_titleartistcopies_soldcumulative_sum
2022_1QIn the Right PlaceDr. John222222
2022_2QIn the Right PlaceDr. John208430
2022_3QIn the Right PlaceDr. John94524
2022_4QIn the Right PlaceDr. John9121436
2023_1QIn the Right PlaceDr. John9122348
2023_2QIn the Right PlaceDr. John562404
2023_3QIn the Right PlaceDr. John5622966

En cada fila, puede ver las ventas de cada trimestre y la suma acumulada, es decir, la suma del trimestre actual y todos los trimestres anteriores. Por ejemplo, el álbum vendió 94 copias en el tercer trimestre de 2022. El total de ventas en 2022 hasta entonces (o en tres trimestres) es: 222 + 208 + 94 = 524.

Ejemplo sintáctico nº 3: OVER (PARTITION BY)

Otra cláusula que puede utilizar en OVER() es PARTITION BY. PARTITION BY se utiliza para dividir la ventana en segmentos más pequeños en función de algunos criterios. Por ejemplo, puedes listar los álbumes, sus datos de ventas para el cuarto trimestre de 2022, y las ventas por género para ese trimestre:

SELECT album_title,
	 artist,
	 copies_sold,
	 album_genre,
	 SUM (copies_sold) OVER(PARTITION BY album_genre) AS sales_by_genre
FROM album_catalogue
WHERE sales_period = '2022_4Q';

De nuevo, utilizamos la misma función de ventana SUM(). Esta vez, sin embargo, utilizamos PARTITION BY para dividir la ventana en segmentos más pequeños en función del género del álbum. Todo lo demás permanece igual.

La consulta arroja el siguiente resultado. Se trata de un análisis de los datos de ventas de álbumes por género en el último trimestre de 2022.

album_titleartistcopies_soldalbum_genresales_by_genre
Wednesday Morning, 3 A.MSimon & Garfunkel809Folk2,081
The Freewheelin' Bob DylanBob Dylan246Folk2,081
Five Leaves LeftNick Drake400Folk2,081
The New Folk Sound of Terry CallierTerry Callier214Folk2,081
BlueJoni Mitchell412Folk2,081
Dirty MindPrince941Funk3,247
Nasty GalBetty Davis369Funk3,247
Cold SweatJames Brown209Funk3,247
A Whole New ThingSly and the Family Stone816Funk3,247
In the Right PlaceDr. John912Funk3,247
Head HuntersHerbie Hancock409Jazz2,075
EnRoute: John Scofield Trio LIVEJohn Scofield Trio612Jazz2,075
In a Silent WayMiles Davis65Jazz2,075
ConciertoJim Hall612Jazz2,075
My Favorite ThingsJohn Coltrane377Jazz2,075

Por ejemplo, la suma acumulada para los álbumes de folk es 809 + 246 + 400 + 214 + 412 = 2.081.

Ejemplo sintáctico nº 4: OVER (ORDER BY PARTITION BY)

También puede utilizar tanto PARTITION BY como ORDER BY en OVER(). Las filas se dividen en segmentos con PARTITION BY y se procesan en un orden determinado por ORDER BY.

Con la consulta siguiente, puedo mostrar todos los datos analíticos de los álbumes y calcular la suma acumulada de cada álbum por separado:

SELECT sales_period,
	 album_title,
	 artist,
	 copies_sold,
	 SUM (copies_sold) OVER(PARTITION BY album_title ORDER BY sales_period ASC) AS cumulative_sum_by_album
FROM album_catalogue;

Lo calculo con la ayuda de la función de ventana SUM(), como hice anteriormente. He dividido la ventana por álbum. Esto significa que la suma se acumulará hasta que la función llegue a la última fila de un álbum determinado. Cuando llega a otro álbum, se reinicia y empieza a acumular la suma desde el principio.

También utilizo ORDER BY para indicar a la función que acumule la suma desde el trimestre más antiguo hasta el más reciente.

sales_periodalbum_titleartistcopies_soldcumulative_sum_by_album
2022_1QA Whole New ThingSly and the Family Stone674674
2022_2QA Whole New ThingSly and the Family Stone257931
2022_3QA Whole New ThingSly and the Family Stone6661,597
2022_4QA Whole New ThingSly and the Family Stone8162,413
2023_1QA Whole New ThingSly and the Family Stone8163,229
2023_2QA Whole New ThingSly and the Family Stone3023,531
2023_3QA Whole New ThingSly and the Family Stone1233,654
2022_1QBlueJoni Mitchell589589
2022_2QBlueJoni Mitchell184773
2022_3QBlueJoni Mitchell2561,029
2022_4QBlueJoni Mitchell4121,441
2023_1QBlueJoni Mitchell4121,853
2023_2QBlueJoni Mitchell991,952
2023_3QBlueJoni Mitchell9952,947
2022_1QWednesday Morning, 3 A.MSimon & Garfunkel1,0431,043
2022_2QWednesday Morning, 3 A.MSimon & Garfunkel4371,480
2022_3QWednesday Morning, 3 A.MSimon & Garfunkel1841,664
2022_4QWednesday Morning, 3 A.MSimon & Garfunkel8092,473
2023_1QWednesday Morning, 3 A.MSimon & Garfunkel8093,282
2023_2QWednesday Morning, 3 A.MSimon & Garfunkel3253,607
2023_3QWednesday Morning, 3 A.MSimon & Garfunkel6124,219

Puedes ver que la suma acumulada para "A Whole New Thing" es de 3.654. El siguiente álbum ('Blue') comienza con la siguiente fila, por lo que la acumulación se reinicia: la suma acumulada es la misma que las ventas individuales del álbum en el primer trimestre de 2022. A continuación, se acumula hasta llegar al siguiente álbum. El resultado llega hasta el último álbum, que en nuestro caso es 'Wednesday Morning, 3 A.M.'.

Con estos ejemplos te he mostrado las formas más comunes de definir marcos de ventana. Pero no son las únicas. También puedes utilizar las cláusulas ROW o RANGE con la sintaxis y los límites que hemos explicado antes. No te preocupes. Verás el uso práctico de esto en ejemplos del mundo real.

He utilizado sólo una función, SUM(), a lo largo de estos ejemplos. Esta es una de las muchas funciones de ventana; revisemos rápidamente algunas de las otras.

¿Cuáles son las más comunes? Funciones de ventana

Las funciones de ventana más comunes pueden dividirse en tres categorías:

  1. Agregado Funciones de ventana:
  • COUNT() - Cuenta el número de filas dentro de una ventana.
  • SUM() - Totaliza valores dados dentro de una ventana.
  • AVG() - Calcula la media de los valores dados dentro de una ventana.
  • MIN() - Encuentra el valor más pequeño dentro de una ventana.
  • MAX() - Encuentra el valor más grande dentro de una ventana.
  1. Clasificación Funciones de ventana:
  • ROW_NUMBER() - Clasifica valores secuencialmente, con diferentes rangos para los valores empatados.
  • RANK() - Ordena los valores utilizando el mismo rango para los valores empatados; omite el siguiente rango después de los empates (por ejemplo, 1, 2, 2, 4).
  • DENSE_RANK() - Clasifica los valores utilizando el mismo rango para los valores empatados; no omite el rango siguiente después de los empates (p. ej., 1,2,2,3,4).
  1. Analítica Funciones de ventana:
  • LEAD() - Obtiene datos a partir de un desplazamiento definido (es decir, un número determinado de filas) después de la fila actual.
  • LAG() - Obtiene datos de un desplazamiento definido (es decir, un número determinado de filas) antes de la fila actual.

Hay más funciones de ventana que pueden resultarle útiles. Consúltalas en nuestra hoja de trucos gratuita de SQL Funciones de ventana.

Ejemplos reales de funciones ventana SQL

Hasta ahora, me he centrado más en la sintaxis de las funciones ventana de SQL. Ahora te mostraré los usos prácticos más comunes de las funciones ventana y cómo pueden ayudar a los analistas de datos en su trabajo.

Estos ejemplos utilizarán el mismo conjunto de datos que antes.

Ejemplo nº 1: Porcentaje del total

Vamos a mostrar información sobre cada álbum y sus ventas en el primer trimestre de 2023. Además, mostraremos las ventas trimestrales por cada género. A continuación, vamos a calcular cuánto contribuye cada álbum (en porcentaje) a las ventas por género.

SELECT album_title,
	 artist,
	 copies_sold,
	 album_genre,
	 SUM(copies_sold) OVER (PARTITION BY album_genre) AS sales_by_genre,
	 (copies_sold*1.0/ SUM(copies_sold) OVER (PARTITION BY album_genre))*100.0 AS percent_of_genre_sales
FROM album_catalogue
WHERE sales_period = '2023_1Q'
ORDER BY album_genre, copies_sold DESC;

Para obtener las ventas por género, vuelvo a utilizar la función de ventana SUM(). En la cláusula OVER(), utilizo sólo PARTITION BY. De este modo, puedo dividir la ventana por el género del álbum.

En la siguiente línea de código, divido las copias vendidas (de cada álbum) y las divido por las ventas por género. Para ello, basta con copiar el cálculo de la línea anterior. A continuación, multiplique el cociente por 100 para obtener el porcentaje. Verás que también he multiplicado copies_sold por 1,0. Esto es para convertir números enteros a valores decimales.

Filtre el trimestre deseado utilizando WHERE. Por último, ordene el resultado alfabéticamente por género y luego descendentemente por copias vendidas.

He aquí el resultado:

album_titleartistcopies_soldalbum_genresales_by_genrepercent_of_genre_sales
Wednesday Morning, 3 A.MSimon & Garfunkel809Folk2,08138.88
BlueJoni Mitchell412Folk2,08119.80
Five Leaves LeftNick Drake400Folk2,08119.22
The Freewheelin' Bob DylanBob Dylan246Folk2,08111.82
The New Folk Sound of Terry CallierTerry Callier214Folk2,08110.28
Dirty MindPrince941Funk3,24728.98
In the Right PlaceDr. John912Funk3,24728.09
A Whole New ThingSly and the Family Stone816Funk3,24725.13
Nasty GalBetty Davis369Funk3,24711.36
Cold SweatJames Brown209Funk3,2476.44
EnRoute: John Scofield Trio LIVEJohn Scofield Trio612Jazz2,07529.49
ConciertoJim Hall612Jazz2,07529.49
Head HuntersHerbie Hancock409Jazz2,07519.71
My Favorite ThingsJohn Coltrane377Jazz2,07518.17
In a Silent WayMiles Davis65Jazz2,0753.13

Comprobemos el cálculo de la primera fila. El álbum de Simon & Garfunkel vendió 809 ejemplares. El total de ventas de álbumes folk de ese trimestre fue de 2.081. Por tanto, el porcentaje de las ventas individuales en las ventas totales del género es de 809/2.081*100 = 38,88%.

La suma de los porcentajes de cada género debería ser 100%. Comprobémoslo en un género folclórico: 38,88% + 19,80% + 19,22% + 11,82% + 10,28 % = 100%.

Función ventana vs. Función agregada vs. GROUP BY

Vuelvo a utilizar la función agregada como función ventana. Podría haber utilizado una simple función agregada SUM() con GROUP BY para obtener las ventas por cada género para el trimestre especificado. ¿Cuál es la diferencia?

Una función ventana permite mostrar tanto datos analíticos como agregados (ventas individuales con ventas por género y el cociente de estos valores), mientras que una función agregada utilizada con GROUP BY colapsaría la fila individual y mostraría sólo el valor agregado (la suma de las ventas del trimestre).

Resuelva este ejercicio para practicar

Utilizando funciones de ventana, reescribe la consulta anterior para que muestre la venta media por género. Además, muestre en qué medida las ventas de cada álbum están por encima o por debajo de la media por género (en porcentaje). Muestra sólo las ventas del tercer trimestre de 2023. Muestra el título del álbum, el artista, las copias vendidas y el género del álbum. Ordena el resultado de forma ascendente por género y ventas de álbumes individuales.

Solución:

SELECT album_title,
	 artist,
	 copies_sold,
	 album_genre,
	 AVG(copies_sold) OVER (PARTITION BY album_genre) AS average_sales_by_genre,
	   ((copies_sold/AVG(copies_sold) OVER (PARTITION BY album_genre))-1)*100 AS pct_from_average	   
FROM album_catalogue
WHERE sales_period = '2023_3Q'
ORDER BY album_genre, copies_sold;

Salida:

album_titleartistcopies_soldalbum_genreaverage_sales_by_genrepct_from_average
The New Folk Sound of Terry CallierTerry Callier283Folk561.6-49.61
Five Leaves LeftNick Drake321Folk561.6-42.84
The Freewheelin' Bob DylanBob Dylan597Folk561.66.30
Wednesday Morning, 3 A.MSimon & Garfunkel612Folk561.68.97
BlueJoni Mitchell995Folk561.677.17
A Whole New ThingSly and the Family Stone123Funk533.4-76.94
Dirty MindPrince169Funk533.4-68.32
In the Right PlaceDr. John562Funk533.45.36
Nasty GalBetty Davis808Funk533.451.48
Cold SweatJames Brown1005Funk533.488.41
ConciertoJim Hall263Jazz464-43.32
My Favorite ThingsJohn Coltrane302Jazz464-34.91
EnRoute: John Scofield Trio LIVEJohn Scofield Trio404Jazz464-12.93
Head HuntersHerbie Hancock542Jazz46416.81
In a Silent WayMiles Davis809Jazz46474.35

Ejemplo #2: Ordenar Datos

En este ejemplo, voy a utilizar una función de ventana para clasificar los datos. Quiero mostrar cada título de álbum distinto y su longitud y ordenarlos por longitud. El álbum más largo será clasificado primero.

SELECT *, 
	 RANK() OVER (ORDER BY album_length DESC) AS album_length_rank
FROM (SELECT DISTINCT album_title,
	       album_length
	FROM album_catalogue) AS distinct_album;

Empecemos explicando la subconsulta: la utilizamos para seleccionar distintos álbumes y su duración.

A continuación, utilizamos la consulta principal para seleccionar todos los datos de la subconsulta. A continuación, utilice la función de ventana RANK() para clasificar los álbumes. También puedes utilizar otras funciones de clasificación, en función de tus datos y tareas.

Para que la clasificación funcione como usted desea, utilice la cláusula ORDER BY en OVER(). Especifique la columna por la que desea clasificar y en qué orden. En este caso, es descendentemente por longitud.

Aquí tienes la clasificación:

album_titlealbum_lengthalbum_length_rank
EnRoute: John Scofield Trio LIVE1:13:481
The Freewheelin' Bob Dylan0:44:142
Head Hunters0:41:523
Five Leaves Left0:41:434
My Favorite Things0:40:255
Nasty Gal0:39:156
In a Silent Way0:38:087
Concierto0:38:028
A Whole New Thing0:38:019
The New Folk Sound of Terry Callier0:37:4110
Blue0:36:1511
Cold Sweat0:33:4312
In the Right Place0:33:2213
Wednesday Morning, 3 A.M0:31:3814
Dirty Mind0:30:1415

Resuelva este ejercicio para practicar

Ordena cada álbum único por sus ventas dentro de su género. Muestra sólo los datos del primer trimestre de 2023. Muestra el título del álbum, sus ventas, género y rango. Si hay álbumes con el mismo número de ventas, ordénalos por igual y no te saltes el siguiente rango.

Solución:

SELECT *, 
	 DENSE_RANK() OVER (PARTITION BY album_genre ORDER BY copies_sold DESC) AS album_sales_rank
FROM (SELECT DISTINCT album_title,
	       copies_sold,
	       album_genre
	FROM album_catalogue
	WHERE sales_period = '2023_1Q') AS distinct_album;

Salida:

album_titlecopies_soldalbum_genrealbum_sales_rank
Wednesday Morning, 3 A.M809Folk1
Blue412Folk2
Five Leaves Left400Folk3
The Freewheelin' Bob Dylan246Folk4
The New Folk Sound of Terry Callier214Folk5
Dirty Mind941Funk1
In the Right Place912Funk2
A Whole New Thing816Funk3
Nasty Gal369Funk4
Cold Sweat209Funk5
EnRoute: John Scofield Trio LIVE612Jazz1
Concierto612Jazz1
Head Hunters409Jazz2
My Favorite Things377Jazz3
In a Silent Way65Jazz4

Ejemplo #3: Total

En este ejemplo, mostraré el periodo de ventas de un álbum concreto, el título, el artista y las copias vendidas. También añadiré un total acumulado de copias vendidas que incluirá tres filas: la fila actual y las dos anteriores. La suma se calculará desde el trimestre más antiguo hasta el más reciente.

SELECT sales_period, 
	 album_title,
	 artist,
	 copies_sold,
	 SUM(copies_sold) OVER (ORDER BY sales_period ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS sales_running_total
FROM album_catalogue
WHERE album_title = 'In a Silent Way';

De nuevo utilizo la función de ventana SUM(). Luego hay un ORDER BY en OVER() para ordenar las ventas y poder sumarlas de forma ascendente.

A continuación, tengo que definir el marco de la ventana móvil. El total móvil debe incluir la fila actual y las dos filas anteriores. Estos son los límites inferior y superior especificados en la cláusula ROWS. El límite inferior son las dos filas anteriores, es decir, BETWEEN 2 PRECEDING. El límite superior es CURRENT ROW. Los dos límites se unen en un marco de ventana utilizando la palabra clave AND.

Quiero mostrar el cálculo del álbum "In a Silent Way" de Miles Davis, así que filtro los datos utilizando WHERE.

Aquí están los totales:

sales_periodalbum_titleartistcopies_soldsales_running_total
2022_1QIn a Silent WayMiles Davis428428
2022_2QIn a Silent WayMiles Davis1,0531,481
2022_3QIn a Silent WayMiles Davis191,500
2022_4QIn a Silent WayMiles Davis651,137
2023_1QIn a Silent WayMiles Davis65149
2023_2QIn a Silent WayMiles Davis218348
2023_3QIn a Silent WayMiles Davis8091,092

Comprobemos el resultado y expliquemos qué es un total acumulado.

Un total acumulado es similar a un total acumulado (o suma), pero no son lo mismo. El total acumulado le dará la suma de la fila actual y todas las filas anteriores, es decir, el marco de la ventana aumenta con cada fila. Un total acumulado es una suma dentro de un marco de ventana definido que mantiene el mismo tamaño pero se desplaza con cada fila. En nuestro caso, la ventana se define como la fila actual y las dos filas anteriores.

Observe los valores resaltados. El total del primer trimestre de 2022 es 428, el mismo que el de la venta individual. No hay filas anteriores, por lo que el total actual sólo incluye la fila actual.

El siguiente total acumulado es 428 + 1.053 = 1.481. Suma la línea actual y la anterior, ya que sólo hay una línea anterior.

El total actual para el tercer trimestre de 2022 es 428 + 1.053 + 19 = 1.500. Esta es la primera vez que obtiene toda la ventana, es decir, la fila actual y las dos filas anteriores.

Al pasar a la fila siguiente, la ventana se moverá pero su tamaño seguirá siendo el mismo. El total para el trimestre siguiente es 428 + 1.053 + 19 + 65 = 1.137. De nuevo, se trata de la fila actual y las dos anteriores. En él intervienen, de nuevo, la fila actual y las dos filas anteriores, pero diferentes en comparación con el trimestre.

Resuelve este ejercicio para practicar

Reescribe la consulta anterior para que calcule el total acumulado del álbum "The New Folk Sound of Terry Callier". El total acumulado debe calcularse desde el trimestre más antiguo hasta el más reciente. Debe incluir cuatro trimestres: los dos anteriores, el trimestre actual y el siguiente. Indique también el periodo de ventas, el título del álbum, el artista y el número de copias vendidas.

Solución:

SELECT sales_period, 
	 album_title,
	 artist,
	 copies_sold,
	 SUM(copies_sold) OVER (ORDER BY sales_period ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING) AS sales_running_total
FROM album_catalogue
WHERE album_title = 'The New Folk Sound of Terry Callier';

Salida:

sales_periodalbum_titleartistcopies_soldsales_running_total
2022_1QThe New Folk Sound of Terry CallierTerry Callier9032,575
2022_2QThe New Folk Sound of Terry CallierTerry Callier4182,789
2022_3QThe New Folk Sound of Terry CallierTerry Callier1,2543,003
2022_4QThe New Folk Sound of Terry CallierTerry Callier2142,641
2023_1QThe New Folk Sound of Terry CallierTerry Callier2142,506
2023_2QThe New Folk Sound of Terry CallierTerry Callier5411,252
2023_3QThe New Folk Sound of Terry CallierTerry Callier2831,038

Ejemplo nº 4: Diferencia entre trimestres

En este último ejemplo, mostraré cómo utilizar las funciones de ventana para calcular la diferencia de ventas entre trimestres:

SELECT *,
	 LAG(quarterly_copies_sold) OVER (ORDER BY sales_period) AS previous_quarter_sales,
	 quarterly_copies_sold - LAG(quarterly_copies_sold) OVER (ORDER BY sales_period) AS quarterly_sales_difference
FROM (SELECT sales_period,
	SUM(copies_sold) AS quarterly_copies_sold
FROM album_catalogue
GROUP BY sales_period) AS quarterly_sales; 

Primero escribo una subconsulta que calcula las ventas totales de cada trimestre. Utilizo la función de agregado SUM() y agrupo los resultados por el periodo de ventas.

A continuación, selecciono todos los datos de la subconsulta en la consulta principal.

Ahora necesito obtener las ventas del trimestre anterior. Escribiré la función de ventana LAG(), que se utiliza para acceder a los valores de las filas anteriores. El valor al que quiero acceder se especifica en la función. En este caso, son las copias trimestrales vendidas de la subconsulta. Al definir el argumento offset, la función me permite definir hasta dónde quiero retroceder. No lo he definido, así que el desplazamiento por defecto es uno. En otras palabras, la función obtendrá los datos de la fila/trimestre anterior. Pero si quieres ir dos filas/cuartos atrás, entonces escribirías LAG(quarterly_copies_sold, 2).

También utilizo ORDER BY en OVER() para asegurarme de que los valores dentro del marco están ordenados del trimestre más antiguo al más reciente.

Este uso de la función ventana es para que quede más claro lo que haré en la siguiente línea de código. Aquí es donde se hace el cálculo real de comparar las ventas del trimestre actual y el anterior. Ahora es sencillo: reste la función ventana definida anteriormente de la columna quarterly_copies_sold.

Aquí está la salida:

sales_periodquarterly_copies_soldprevious_quarter_salesquarterly_sales_difference
2022_1Q9,519NULLNULL
2022_2Q7,5819,519-1,938
2022_3Q4,2737,581-3,308
2022_4Q7,4034,2733,130
2023_1Q7,4037,4030
2023_2Q4,9567,403-2,447
2023_3Q7,7954,9562,839

No hay valores anteriores para 2022_1Q, ya que no hay trimestre anterior. Las ventas trimestrales para 2022_2Q son 7.581. Las ventas del trimestre anterior fueron 9.519. El cálculo muestra que las ventas actuales son 1.938 ejemplares (7.581 - 9.519) inferiores a las ventas del trimestre anterior.

Puedes analizar el resto de la producción de la misma manera.

Resuelva este ejercicio para practicar

Vuelva a escribir la consulta anterior para que muestre la diferencia entre las ventas trimestrales sobre una base interanual; por ejemplo, compare el primer trimestre de 2023 con el primer trimestre de 2022. Muestre el período de ventas, las copias vendidas en el trimestre, las ventas del mismo trimestre del año anterior y la diferencia interanual entre los trimestres.

Solución:

SELECT *,
	 LAG(quarterly_copies_sold, 4) OVER (ORDER BY sales_period) AS year_over_year_sales,
	 quarterly_copies_sold - LAG(quarterly_copies_sold, 4) OVER (ORDER BY sales_period) AS year_over_year_difference
FROM (SELECT sales_period,
	   SUM(copies_sold) AS quarterly_copies_sold
FROM album_catalogue
GROUP BY sales_period) AS quarterly_sales; 

Salida:

sales_periodquarterly_copies_soldyear_over_year_salesyear_over_year_difference
2022_1Q9,519NULLNULL
2022_2Q7,581NULLNULL
2022_3Q4,273NULLNULL
2022_4Q7,403NULLNULL
2023_1Q7,4039,519-2,116
2023_2Q4,9567,581-2,625
2023_3Q7,7954,2733,522

Si quieres más, aquí tienes ejemplos adicionales de funciones ventana. Para materiales de práctica, echa un vistazo a estos 11 ejercicios de funciones ventana de SQL.

SQL Funciones de ventana: Una Ventana a un Mejor Análisis de Datos

Este resultó ser un artículo bastante completo sobre las funciones ventana de SQL. Aprendiste las funciones ventana y como funciona cada parte crucial de su sintaxis.

También sabes que hay varias categorías de funciones ventana. Las más utilizadas son las funciones ventana de agregación, clasificación y análisis. Los ejemplos prácticos le mostraron cómo se pueden utilizar las funciones ventana en tareas comunes de análisis de datos.

Espero que no se haya saltado los ejercicios del artículo. Si lo ha hecho, le recomiendo una vez más que los resuelva. Sólo a través de la práctica podrá entender realmente en qué consisten las funciones ventana de SQL.

El recurso más rico para aprender y practicar es nuestro Funciones de ventana curso. Es un curso interactivo que tiene más de 200 ejercicios prácticos y cubre toda la sintaxis de las funciones ventana. Si tienes previstas entrevistas de trabajo, asegúrate de repasar estas preguntas de entrevista sobre funciones de ventana de SQL. Buena suerte, ¡y sigue aprendiendo SQL!