¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

PARTITION BY y media móvil

Después de esta lección: Puedo ordenar dentro de cada grupo y calcular una media sobre una ventana móvil.

Lección de 60 minSin comandos

Qué hacen PARTITION BY y los marcos

PARTITION BY reparte las filas en grupos y calcula la función de ventana dentro de cada grupo, sin juntar las filas. Un marco limita cuántas filas vecinas entran en el cálculo, por ejemplo para una media móvil.

Sirve para dos preguntas habituales: quién es el mejor de cada grupo y cuánto se alquiló de media los últimos tres días.

Al terminar esta lección

Nota

Puedo ordenar dentro de cada grupo y calcular una media sobre una ventana móvil.

Palabras clave

PalabraQué significaEjemplo
Particiónun grupo de filas dentro de la ventana
PARTITION BYreparte las filas en particionesPARTITION BY class_group
Marcolas filas vecinas que entran en el cálculoROWS BETWEEN 2 PRECEDING AND CURRENT ROW
Media móvilla media de la fila actual y las anteriores
Subconsultauna consulta escrita dentro de otra

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

PARTITION BY reparte las filas en grupos

PARTITION BY class_group hace que la función empiece de nuevo en cada grupo. El primer puesto de la clase A y el de la clase B son dos puestos distintos.

A diferencia de GROUP BY, todas las filas siguen ahí. Sirve con RANK, con ROW_NUMBER y con agregados como AVG.

Ejemplo resuelto: el puesto dentro de cada grupo

studentclass_groupmarkplace
MateoA851
SofíaA851
LucíaA723
HugoA604
ValeriaB911
DanielB782
AdriánB782
PaulaB664
CarmenC881
IreneC702
PabloC543

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Pruébalo: la media de cada grupo

Código: duckdb
-- La media de cada grupo, junto a cada alumno.
select student, class_group, mark,
  round(avg(mark) over (partition by class_group), 1) as group_avg
from marks
order by student_id;
-- Cambia avg por max y pulsa Run.

Quedarse con los mejores de cada grupo

Para quedarte con los dos mejores de cada grupo, numera con ROW_NUMBER y PARTITION BY. Después filtra n <= 2 en la consulta de fuera.

Añade un segundo criterio al ORDER BY, como student_id. Así el desempate es siempre el mismo.

DuckDB tiene también QUALIFY, que filtra por una ventana sin escribir la subconsulta.

Pruébalo: los dos mejores con una subconsulta

Código: duckdb
-- Los dos mejores de cada grupo, con una subconsulta.
select student, class_group, mark
from (
  select *,
    row_number() over (partition by class_group order by mark desc, student_id) as n
  from marks
)
where n <= 2
order by class_group, n;
-- Cambia 2 por 1 y pulsa Run.

Pruébalo: los mismos con QUALIFY

Código: duckdb
-- Lo mismo con QUALIFY, sin subconsulta.
select student, class_group, mark
from marks
qualify row_number() over (partition by class_group order by mark desc, student_id) <= 2
order by class_group, mark desc, student_id;
-- Cambia desc por asc para ver los dos peores.

Un marco elige las filas vecinas

ROWS BETWEEN 2 PRECEDING AND CURRENT ROW toma la fila actual y las dos anteriores. Con ese marco, AVG da una media móvil de tres días.

Al principio no hay tres filas todavía. El marco usa las que existen, y por eso el primer valor es la media de una sola fila.

Ejemplo resuelto: una media móvil de tres días

dayridesFilas en el marcomoving_avg
2026-04-0640140.0
2026-04-0746243.0
2026-04-0852346.0
2026-04-0931343.0
2026-04-1058347.0
2026-04-1170353.0
2026-04-1264364.0

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Pruébalo: la media móvil

Código: duckdb
-- La media de cada día y los dos anteriores.
select day, rides,
  round(avg(rides) over (order by day rows between 2 preceding and current row), 1) as moving_avg
from daily_rides
order by day;
-- Cambia 2 preceding por 1 preceding y pulsa Run.

Un error frecuente

Advertencia

Mucha gente cree que SUM(x) OVER (ORDER BY x) suma fila a fila. Con empates, el marco por defecto trata las filas iguales como un bloque y les da el mismo total. Escribe ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW para ir de una en una.

Ejemplo resuelto: dos totales con empates

student_idmarkMarco por defectoCon ROWS
1170250250
678478400
878478478
285648563
385648648

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.