Totales acumulados y el marco de la ventana
Avanzadosum(valor) OVER (PARTITION BY grupo ORDER BY fecha) da un total acumulado por grupo. El marco (frame) decide qué filas entran en cada suma. Con ORDER BY y sin marco explícito, PostgreSQL usa RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, que incluye también las filas empatadas con la actual.
Sintaxis
sum(valor) OVER (
PARTITION BY grupo
ORDER BY fecha, id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)Ejemplo
SELECT
o.channel AS canal,
to_char(o.created_at, 'YYYY-MM-DD') AS dia,
o.id AS pedido,
o.total_amount AS total,
sum(o.total_amount) OVER (
PARTITION BY o.channel
ORDER BY o.created_at::date
) AS acumulado_range,
sum(o.total_amount) OVER (
PARTITION BY o.channel
ORDER BY o.created_at::date, o.id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS acumulado_rows
FROM orders AS o
WHERE o.currency = 'UYU'
AND o.status <> 'cancelled'
AND o.channel IN ('app', 'web')
AND o.created_at >= '2025-08-01'
AND o.created_at < '2025-08-11'
ORDER BY canal, dia, pedido;Resultado
| canal | dia | pedido | total | acumulado_range | acumulado_rows |
|---|---|---|---|---|---|
| app | 2025-08-02 | 4733 | 13923.69 | 14853.24 | 13923.69 |
| app | 2025-08-02 | 7584 | 929.55 | 14853.24 | 14853.24 |
| app | 2025-08-07 | 10046 | 32055.60 | 62842.85 | 46908.84 |
| app | 2025-08-07 | 10715 | 15934.01 | 62842.85 | 62842.85 |
| web | 2025-08-03 | 11074 | 5083.46 | 5083.46 | 5083.46 |
| web | 2025-08-08 | 8968 | 952.22 | 6035.68 | 6035.68 |
| web | 2025-08-09 | 14738 | 9926.40 | 15962.08 | 15962.08 |
Cómo leerlo
El acumulado vuelve a empezar en cada canal por el PARTITION BY. En los días con dos pedidos las columnas difieren: con el marco por defecto (RANGE) los dos pedidos del mismo día son «pares» (empatan en el ORDER BY) y ambos muestran el total del día completo. Con ROWS y el id como desempate, el acumulado avanza pedido por pedido.
Error común
Así no
SELECT created_at::date AS dia, total_amount,
sum(total_amount) OVER (ORDER BY created_at::date) AS acumulado
FROM orders
WHERE currency = 'UYU';Ordenar la ventana por una columna con empates y esperar un acumulado fila por fila. Con el marco por defecto, los pedidos del mismo día reciben el mismo acumulado. Si quieres un valor por fila, usa ROWS con un desempate único; si quieres el total al cierre de cada día, agrupa primero por día y acumula después.