Skip to content
Empieza gratis

¿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_idfechamontoacumulado
10092025-01-2312804080
10142025-02-0623908050
10152025-02-0615808050
10282025-02-218908940

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:

SQL
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
El marco por omisión cuando hay ORDER BY dentro de OVER.

"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 el ORDER 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.

  1. ¿Hay empates en el ORDER BY del OVER?

    • Camino 1 de 2: no

      1. ROWS y RANGE dan lo mismo

        cada fila es única en ese orden

      Aquí termina.

    • Camino 2 de 2: sí

      1. RANGE suma a los empatados juntos

        ROWS avanza una fila a la vez

      2. Usa ROWS y agrega un desempate

        por ejemplo, pedido_id

      Aquí termina.

Para que el acumulado avance pedido por pedido necesitas dos cosas:

  1. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, para que cada fila sume solo hasta ella.
  2. Un desempate en el ORDER BY (fecha, pedido_id). Sin él, ROWS avanza 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

ColumnaTipo
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_idclientefechamonto
1001Fer2025-01-03850
1002Diego2025-01-041360
1003Beto2025-01-11600

Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras.

Listo para ejecutar tu consulta.

Ejecútalo tú

¿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.

Comprueba lo que sabes: Escribes SUM(monto) OVER (ORDER BY fecha) sin marco, y dos pedidos tienen la misma fecha. ¿Qué marco está usando DuckDB?