Un total acumulado suma, en cada fila, todo lo anterior más la fila actual: las ventas acumuladas del año, el saldo de una cuenta tras cada movimiento, las unidades vendidas hasta la fecha… Antes de las funciones de ventana había que resolverlo con subconsultas correlacionadas, lentas y difíciles de leer. Hoy basta con SUM(...) OVER (ORDER BY ...).

Total acumulado

El importe acumulado de la tienda pedido a pedido, por orden de fecha:

PostgreSQL en tu navegador · Ctrl+Enter para ejecutar · los cambios se deshacen al terminar
fechaPedido producto totalPrecio acumulado
2022-01-21 Xbox series X 999,98 999,98
2022-06-20 MacBook Pro M1 2449,50 3449,48
2022-07-09 Xiami Mi 11 4304,25 7753,73
2022-07-18 Play Station 5 2199,80 9953,53
2022-09-01 Echo DOT 3 1999,50 11953,03
2022-09-01 Echo DOT 4 2999,50 14952,53
2022-09-05 Nintendo Switch 899,97 15852,50
2022-09-10 Horno Balay 1399,10 17251,60

La última fila coincide con el total de ventas, 17.251,60 €. La línea ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW es el marco de la ventana: le dice al motor qué filas sumar en cada momento. Aquí, desde la primera (UNBOUNDED PRECEDING) hasta la actual (CURRENT ROW).

El marco de la ventana

El marco se define con ROWS BETWEEN inicio AND fin, donde cada extremo puede ser:

Extremo Significado
UNBOUNDED PRECEDING La primera fila de la partición
n PRECEDING n filas antes de la actual
CURRENT ROW La fila actual
n FOLLOWING n filas después de la actual
UNBOUNDED FOLLOWING La última fila de la partición

ROWS frente a RANGE: cuidado con los empates

Si escribes solo ORDER BY sin marco, el motor usa por defecto RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. La diferencia con ROWS aparece con los empates: RANGE trata todas las filas con el mismo valor de ordenación como una sola, y les da a todas el mismo acumulado.

PostgreSQL en tu navegador · Ctrl+Enter para ejecutar · los cambios se deshacen al terminar
fechaPedido producto totalPrecio conRows conRange
2022-07-09 Xiami Mi 11 4304,25 4304,25 4304,25
2022-07-18 Play Station 5 2199,80 6504,05 6504,05
2022-09-01 Echo DOT 3 1999,50 8503,55 11503,05
2022-09-01 Echo DOT 4 2999,50 11503,05 11503,05
2022-09-05 Nintendo Switch 899,97 12403,02 12403,02
2022-09-10 Horno Balay 1399,10 13802,12 13802,12

Los dos Echo DOT son del 1 de septiembre. Con ROWS el acumulado sube en dos pasos; con RANGE los dos reciben ya la suma de ambos. Ninguno es incorrecto, pero casi siempre lo que se espera es ROWS, así que conviene escribir el marco explícitamente.

En SQL Server, ROWS además es más rápido que RANGE, que necesita guardar el resultado intermedio en disco. Es otra razón para escribir siempre el marco.

Acumulado por cliente

Con PARTITION BY el acumulado vuelve a cero en cada grupo:

PostgreSQL en tu navegador · Ctrl+Enter para ejecutar · los cambios se deshacen al terminar
nombre fechaPedido producto totalPrecio acumuladoCliente
Alejandro 2022-09-05 Nintendo Switch 899,97 899,97
Ana 2022-07-09 Xiami Mi 11 4304,25 4304,25
Fernando 2022-06-20 MacBook Pro M1 2449,50 2449,50
Luis 2022-09-01 Echo DOT 3 1999,50 1999,50
Luis 2022-09-01 Echo DOT 4 2999,50 4999,00
María 2022-01-21 Xbox series X 999,98 999,98
María 2022-07-18 Play Station 5 2199,80 3199,78

Media móvil

Cambiando el marco a “las dos filas anteriores y la actual” se obtiene una media móvil de tres periodos, que suaviza los picos y se usa mucho para ver tendencias:

PostgreSQL en tu navegador · Ctrl+Enter para ejecutar · los cambios se deshacen al terminar
fechaPedido producto totalPrecio mediaMovil3
2022-01-21 Xbox series X 999,98 999,98
2022-06-20 MacBook Pro M1 2449,50 1724,74
2022-07-09 Xiami Mi 11 4304,25 2584,58
2022-07-18 Play Station 5 2199,80 2984,52
2022-09-01 Echo DOT 3 1999,50 2834,52
2022-09-01 Echo DOT 4 2999,50 2399,60
2022-09-05 Nintendo Switch 899,97 1966,32
2022-09-10 Horno Balay 1399,10 1766,19

En las dos primeras filas no hay todavía tres pedidos, así que la media se calcula con los que hay: uno y dos.

Porcentaje acumulado

Juntando un acumulado con un total (OVER ()) sale el porcentaje acumulado, la base de un análisis de Pareto (¿qué pedidos suman el 80 % de las ventas?):

PostgreSQL en tu navegador · Ctrl+Enter para ejecutar · los cambios se deshacen al terminar
producto totalPrecio porcentajeAcumulado
Xiami Mi 11 4304,25 24,9
Echo DOT 4 2999,50 42,3
MacBook Pro M1 2449,50 56,5
Play Station 5 2199,80 69,3
Echo DOT 3 1999,50 80,9
Horno Balay 1399,10 89,0
Xbox series X 999,98 94,8
Nintendo Switch 899,97 100,0

Los cinco pedidos más grandes ya suman más del 80 % de lo vendido.

Practica

  1. Calcula las unidades acumuladas (numeroProductos) por orden de fecha.
  2. Cambia la media móvil para que use la fila anterior, la actual y la siguiente.
  3. Usa LAST_VALUE con el marco ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING para mostrar en cada fila el último producto pedido.