Particiones en las funciones de ventana

En el artículo anterior ya mencionamos brevemente qué son las particiones y cómo se usan en las funciones de ventana. Ha llegado el momento de verlas con más detalle 🤓.

Qué es una partición

Sirven para segmentar los datos y permiten hacer un análisis más detallado y cálculos como agregaciones o rankings dentro de cada uno de esos grupos.

Por ejemplo, si dividimos en particiones por tipo una tabla con los precios de los alojamientos, podemos calcular en una columna aparte el precio medio de cada tipo de alojamiento.

Esquema de división en particiones

Uso de particiones en SQL

Para usar una partición junto con una función de ventana, hay que seguir esta sintaxis:

MySQL 8.4
SELECT funcion_ventana(campo_tabla)
OVER (
    PARTITION BY columna_particion [, ...]
)
  • [ ]parte opcional
  • ...se puede repetir
funcion_ventana

La función que se calcula sobre la ventana, por ejemplo AVG o SUM.

campo_tabla

La columna cuyos valores se pasan a la función, por ejemplo price en AVG(price).

columna_particion

La columna por la que las filas se dividen en particiones: las filas con el mismo valor van a la misma. Puedes indicar varias columnas separadas por comas.

Ejemplo de uso

Veamos ahora con un ejemplo sencillo cómo se usa una partición junto con una función de ventana.

Para ello, tomemos la tabla Rooms, en concreto las columnas home_type y price:

MySQL 8.4
SELECT home_type, price FROM Rooms;
home_typeprice
Private room149
Entire home/apt225
Private room150
Entire home/apt89
Entire home/apt80
Entire home/apt200
Private room60
Private room79
Private room79
Entire home/apt150
Entire home/apt135
Private room85
Private room89
Private room85
Entire home/apt120
Entire home/apt140
Entire home/apt215
Private room140
Entire home/apt99
Entire home/apt190
Entire home/apt299
Private room130
Private room80
Private room110
Entire home/apt120
Private room60
Private room80
Entire home/apt150
Private room44
Entire home/apt180
Private room50
Private room52
Private room55
Private room50
Private room70
Private room89
Private room35
Entire home/apt85
Private room150
Shared room40
Private room68
Entire home/apt120
Private room120
Private room135
Entire home/apt150
Entire home/apt150
Private room130
Entire home/apt110
Entire home/apt115
Private room80

Podemos ver que todos los alojamientos en alquiler se dividen en 3 categorías: «Private room», «Entire home/apt» y «Shared room».

Cada categoría de alojamiento tiene su propio rango de precios. Para saber el precio medio de una categoría concreta y compararlo con el precio actual, las funciones de ventana vienen como anillo al dedo.

Para ello, añadimos a nuestra tabla de resultados otra columna, avg_price, que calculará el precio medio por categoría. Quedaría así:

MySQL 8.4
SELECT
    home_type, price,
    AVG(price) OVER (PARTITION BY home_type) AS avg_price
FROM Rooms
home_typepriceavg_price
Entire home/apt225148.6667
Entire home/apt180148.6667
Entire home/apt150148.6667
Entire home/apt85148.6667
Entire home/apt120148.6667
Entire home/apt120148.6667
Entire home/apt299148.6667
Entire home/apt190148.6667
Entire home/apt99148.6667
Entire home/apt215148.6667
Entire home/apt140148.6667
Entire home/apt120148.6667
Entire home/apt150148.6667
Entire home/apt135148.6667
Entire home/apt150148.6667
Entire home/apt110148.6667
Entire home/apt115148.6667
Entire home/apt200148.6667
Entire home/apt150148.6667
Entire home/apt80148.6667
Entire home/apt89148.6667
Private room6889.4286
Private room5089.4286
Private room7089.4286
Private room8089.4286
Private room8989.4286
Private room14989.4286
Private room3589.4286
Private room15089.4286
Private room13089.4286
Private room12089.4286
Private room13589.4286
Private room13089.4286
Private room15089.4286
Private room6089.4286
Private room7989.4286
Private room7989.4286
Private room8589.4286
Private room8989.4286
Private room8589.4286
Private room14089.4286
Private room5589.4286
Private room8089.4286
Private room11089.4286
Private room6089.4286
Private room8089.4286
Private room4489.4286
Private room5089.4286
Private room5289.4286
Shared room4040

¿Qué ocurre exactamente en la línea que hemos añadido?

  • PARTITION BY home_type divide todos los registros en particiones distintas según los valores únicos de la columna home_type.
  • Después, para cada registro, AVG(price) calcula el precio medio (price) dentro de su partición (home_type).

El resultado de esta parte de la consulta es la columna avg_price, en la que, para cada registro, aparece el precio medio de su categoría de alojamiento (home_type).

Particiones por varias columnas

También se puede particionar por varias columnas. Esto permite crear segmentos de análisis más complejos y precisos.

Por ejemplo, para nuestra tabla Rooms podemos crear particiones a partir de 2 columnas: la categoría de alojamiento home_type y si el alojamiento tiene televisor, has_tv.

Ejemplo de consulta con particiones por dos columnas:

MySQL 8.4
SELECT
    home_type, has_tv, price,
    AVG(price) OVER (PARTITION BY home_type, has_tv) AS avg_price
    FROM Rooms
home_typehas_tvpriceavg_price
Entire home/apt0225170
Entire home/apt0180170
Entire home/apt080170
Entire home/apt0200170
Entire home/apt0150170
Entire home/apt0150170
Entire home/apt0190170
Entire home/apt0215170
Entire home/apt0140170
Entire home/apt199132.6667
Entire home/apt185132.6667
Entire home/apt1150132.6667
Entire home/apt1120132.6667
Entire home/apt1120132.6667
Entire home/apt1299132.6667
Entire home/apt1120132.6667
Entire home/apt1135132.6667
Entire home/apt1150132.6667
Entire home/apt1110132.6667
Entire home/apt189132.6667
Entire home/apt1115132.6667
Private room08578.5455
Private room03578.5455
Private room015078.5455
Private room05578.5455
Private room05278.5455
Private room05078.5455
Private room06878.5455
Private room06078.5455
Private room013578.5455
Private room08578.5455
Private room08978.5455
Private room112096.4706
Private room18096.4706
Private room114996.4706
Private room113096.4706
Private room18996.4706
Private room17096.4706
Private room15096.4706
Private room14496.4706
Private room18096.4706
Private room16096.4706
Private room111096.4706
Private room18096.4706
Private room113096.4706
Private room114096.4706
Private room17996.4706
Private room17996.4706
Private room115096.4706
Shared room14040

Aquí, PARTITION BY home_type, has_tv crea particiones únicas para cada combinación de home_type y has_tv, lo que permite calcular el precio medio de la categoría de alojamiento actual con o sin televisor.

Particiones por 2 columnas