¿Por qué mi suma acumulada en SQL repite números?
Mira a dos pedidos del mismo día recibir el mismo acumulado, entiende el marco RANGE y arréglalo con ROWS.
Curso gratis. Tu Maestro, una IA, .
Corre el código del ejercicio de abajo tal como está. Es la suma acumulada de los pedidos de Elena, con la receta de la página anterior. Antes de mirar el resultado, fíjate en el 6 de febrero de 2025: Elena hizo dos pedidos ese día, el 1014 (2390 pesos) y el 1015 (1580 pesos). Hasta el día anterior llevaba 4080. Contesta la pregunta de abajo.
Comprueba lo que sabes: Con SUM(monto) OVER (PARTITION BY cliente ORDER BY fecha), ¿qué acumulado muestran los pedidos 1014 y 1015 de Elena, los dos del 6 de febrero?
Así salió en el sandbox de Maestro:
| pedido_id | fecha | monto | acumulado |
|---|---|---|---|
| 1009 | 2025-01-23 | 1280 | 4080 |
| 1014 | 2025-02-06 | 2390 | 8050 |
| 1015 | 2025-02-06 | 1580 | 8050 |
| 1028 | 2025-02-21 | 890 | 8940 |
Los dos pedidos muestran el mismo acumulado. No es un error. Es la regla del marco por omisión.
Cuando escribes ORDER BY dentro de OVER y no dices nada del marco, DuckDB usa este marco:
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"Desde el inicio de la partición hasta la fila actual". El detalle está en qué significa "fila actual":
- Con
RANGE, la fila actual incluye a sus empates: todas las filas con el mismo valor en elORDER BY. Para el pedido 1014, "hasta la fila actual" ya incluye al 1015, porque tienen la misma fecha. - Con
ROWS, la fila actual es solo esa fila.
El diagrama resume cuándo importa.
¿Hay empates en el ORDER BY del OVER?
Camino 1 de 2: no
ROWS y RANGE dan lo mismo
cada fila es única en ese orden
Aquí termina.
Camino 2 de 2: sí
RANGE suma a los empatados juntos
ROWS avanza una fila a la vez
Usa ROWS y agrega un desempate
por ejemplo, pedido_id
Aquí termina.
Para que el acumulado avance pedido por pedido necesitas dos cosas:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, para que cada fila sume solo hasta ella.- Un desempate en el
ORDER BY(fecha, pedido_id). Sin él,ROWSavanza fila por fila, pero nada dice cuál de los dos pedidos del mismo día va primero.
Inténtalo
Arregla la consulta de abajo para que los pedidos 1014 y 1015 tengan acumulados distintos. Si cambias a ROWS y sigue sin cuadrar, pregúntale a tu Maestro.
Cambia el OVER para que el acumulado de Elena avance un pedido a la vez: escribe el marco ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW y desempata con pedidoid. Deja las mismas columnas y el mismo orden final. Terminaste cuando el pedido 1014 dice 6470 y el 1015 dice 8050.
Tu turno
Cambia el OVER para que el acumulado de Elena avance un pedido a la vez: escribe el marco ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW y desempata con pedido_id. Deja las mismas columnas y el mismo orden final. Terminaste cuando el pedido 1014 dice 6470 y el 1015 dice 8050.
Tablas: pedidos (pedido_id, cliente, fecha, monto)
pedidos · 60 filas
| Columna | Tipo |
|---|---|
| pedido_id Número del pedido; crece con el orden en que se registró. | BIGINT |
| cliente Nombre del cliente. | VARCHAR |
| fecha Día del pedido, sin hora. | DATE |
| monto Monto del pedido, en pesos. | BIGINT |
Primeras filas
| pedido_id | cliente | fecha | monto |
|---|---|---|---|
| 1001 | Fer | 2025-01-03 | 850 |
| 1002 | Diego | 2025-01-04 | 1360 |
| 1003 | Beto | 2025-01-11 | 600 |
Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras. Tab agrega sangría; para salir del editor, presiona Escape y luego Tab.
Listo para ejecutar tu consulta.
¿Cuál es el "correcto"? Depende de la pregunta. Si quieres el acumulado al cierre de cada día, el RANGE por omisión es justo lo que necesitas: los dos pedidos del 6 de febrero muestran lo que llevaba Elena al terminar ese día. Si quieres el acumulado después de cada pedido, usa ROWS con desempate. Lo importante es elegirlo tú, en vez de que lo elija la regla por omisión.
En una entrevista casi nunca te preguntan "¿qué es RANGE?". A veces te dan una tabla de transacciones con varias por día, piden "el saldo después de cada transacción" y esperan ver si tu acumulado repite números. Otra versión: "¿por qué estas dos consultas dan resultados distintos?", con una que ordena por fecha y otra por fecha e id. Si explicas el marco por omisión y lo escribes explícito, contestaste. Si quieres que tu Maestro te haga la versión del saldo, pídeselo.
Revisa tus consultas: busca cada OVER (... ORDER BY ...) que use SUM, AVG o COUNT sin marco escrito. Si la columna del ORDER BY puede repetirse (fechas sin hora, por ejemplo), decide si quieres el cierre del día o el valor después de cada fila, y escribe el marco. PostgreSQL documenta la misma regla por omisión: con ORDER BY, el marco llega hasta la fila actual más las filas que empatan con ella.