English

Manual de campo · trampas de SQL

¿Por qué el saldo acumulado repite el mismo número en dos filas distintas?

sum(...) OVER (ORDER BY fecha) sin especificar el marco usa RANGE por defecto: agrupa todas las filas con la misma fecha en un único bloque, y todas enseñan el mismo acumulado.

Cuándo aparece

Cualquier saldo corrido, total acumulado o ranking calculado con una window function cuando el ORDER BY tiene valores empatados (dos movimientos el mismo día, dos ventas a la misma hora).

Ejemplo

Mal: sin marco explícito, los empatados comparten fila

SELECT fecha, importe,
       sum(importe) OVER (ORDER BY fecha) AS saldo
FROM movimientos;
-- dos apuntes del mismo día caen en el mismo RANGE:
-- ambos enseñan el saldo ya sumando los dos, ninguno el saldo intermedio

Bien: ROWS, que cuenta filas y no valores empatados

SELECT fecha, importe,
       sum(importe) OVER (
         ORDER BY fecha
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS saldo
FROM movimientos;

Cuando hay ORDER BY en una window function pero no se especifica el marco, el motor asume RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, y RANGE agrupa por *valor*, no por fila: todas las filas con el mismo valor de ORDER BY quedan en el mismo punto del marco, así que todas ven la misma suma, la de después de sumarlas todas. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW avanza fila por fila sin que le importen los empates: la primera de las dos filas del mismo día ve el saldo antes de sumar la segunda, y la segunda ve el saldo con las dos. La regla práctica: si la palabra es 'saldo corrido' o 'acumulado hasta esta fila', casi siempre quieres ROWS, no el RANGE que se aplica sin pedirlo.

Esta trampa está escondida en un caso de verdad, con datos de verdad.

Jugar el caso 1 gratis →

Trampas relacionadas