Skip to content
Empieza gratis

¿Cómo hago una suma acumulada en SQL?

Calcula las ventas acumuladas del año de cada sucursal, mes por mes, agregando ORDER BY dentro de OVER.

Curso gratis. Tu Maestro, una IA, .

En una hoja de cálculo, una suma acumulada es una fórmula que arrastras: "esta celda más la de arriba". En SQL no hay celdas de arriba, pero hay ventanas.

Ya escribiste SUM(ventas) OVER (PARTITION BY sucursal), que pone el total del año en cada fila. Agrégale ORDER BY mes dentro del OVER y pasa algo nuevo: cada fila suma desde el primer mes de su sucursal hasta ella misma.

Eso es porque, cuando hay ORDER BY dentro de OVER, el marco (las filas de la ventana que entran en el cálculo) va del inicio de la partición a la fila actual. Sin ORDER BY, el marco es toda la partición.

SQL · línea 3
SUM(ventas) OVER (
  PARTITION BY sucursal
  ORDER BY mes
) AS acumulado
La línea 3 es la diferencia entre el total del año y el acumulado.

Fila por fila

Así quedaron los primeros cuatro meses de Centro en el sandbox de Maestro:

mesventasacumulado
2025-01-01165100165100
2025-02-01155700320800
2025-03-01178700499500
2025-04-01175800675300

Piensa en el marco como una ventana que se estira. En enero, el marco de Centro tiene una sola fila, así que el acumulado es igual a las ventas. En febrero entran enero y febrero. En marzo, los tres. La función es la misma SUM de siempre: lo que cambia de fila a fila es cuántas filas le tocan. Y cuando la consulta pasa a la primera fila de Norte, el marco vuelve a empezar desde cero, porque PARTITION BY lo encierra en su sucursal.

La gráfica dibuja el acumulado de las tres sucursales. Vega-Lite también tiene ventanas: cada línea sale de una sum con un marco que va del inicio hasta la fila actual, que es lo mismo que acabas de leer en SQL.

Datos sintéticos del curso (CC0). Cada línea es la ventana sum de Vega-Lite con marco del inicio a la fila actual, una partición por sucursal.

Inténtalo

Calcula el acumulado del año de cada sucursal. Antes de escribirlo, contesta la pregunta de abajo. Si tu acumulado no reinicia en cada sucursal, pregúntale a tu Maestro.

Comprueba lo que sabes: Antes de correr: ¿qué número va a salir en la columna acumulado en diciembre de Centro?

Regresa sucursal, mes, ventas y acumulado: las ventas desde enero hasta ese mes, dentro de su sucursal. Ordena por sucursal, mes. Terminaste cuando diciembre de Centro dice 2174100.

Tu turno

Regresa sucursal, mes, ventas y acumulado: las ventas desde enero hasta ese mes, dentro de su sucursal. Ordena por sucursal, mes. Terminaste cuando diciembre de Centro dice 2174100.

Tablas: ventas_mensuales (sucursal, mes, ventas)

ventas_mensuales · 35 filas

ColumnaTipo
sucursal Nombre de la sucursal: Centro, Norte o Sur.VARCHAR
mes Primer día del mes que resume la fila.DATE
ventas Ventas del mes, en pesos.BIGINT

Primeras filas

sucursalmesventas
Centro2025-01-01165100
Centro2025-02-01155700
Centro2025-03-01178700

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ú

Diciembre de Centro dice 2174100: el mismo total del año que viste en la primera página. Tiene sentido: en diciembre el marco ya abarca los 12 meses.

Aquí el ORDER BY de adentro hace más que ordenar: cambia qué filas entran en la suma. Con SUM, AVG, COUNT y compañía, agregar o quitar ese ORDER BY cambia el resultado.

Cuando la tabla no es perfecta

Un valor vacío. SUM ignora los NULL, también dentro de una ventana. En el sandbox, con tres filas que valían 100, NULL y 50, el acumulado dio 100, 100 y 150: la fila vacía repite el acumulado anterior, no lo convierte en NULL. Si un NULL en tu tabla significa "no se capturó", ese 100 repetido se ve como un mes sin ventas, y nadie lo va a notar.

Un mes que falta. A Sur le falta junio, y aquí no pasa nada raro: el acumulado de julio sigue siendo todo lo vendido hasta julio. La suma no compara con "el mes anterior" como LAG. Lo que sí pasa es que tu reporte tiene 11 filas para Sur, y si alguien busca "el acumulado a junio", no lo encuentra.

Varios años. Esta tabla es solo de 2025. Si la tuya tiene varios años y quieres el acumulado del año en curso, el año también va en la partición, para que el marco reinicie cada enero:

SQL · línea 2
SUM(ventas) OVER (
  PARTITION BY sucursal, year(mes)
  ORDER BY mes
) AS acumulado_del_año
Con el año en PARTITION BY, el acumulado vuelve a empezar en cada enero. year() es la función de DuckDB.

En cada fila tienes el acumulado, y con OVER () (o PARTITION BY sucursal) tienes el total. Dividir uno entre otro da el porcentaje acumulado: qué parte del año ya se vendió en cada mes. Primero míralo resuelto con otra sucursal, y abre cada paso después de intentar adivinarlo.

El porcentaje acumulado de Norte

Ejemplo resuelto · 4 pasos

Con ventas_mensuales: para la sucursal Norte, el acumulado de cada mes, el total del año y qué porcentaje del año llevaba vendido al cierre de cada mes. ¿En qué mes pasó la mitad?

Piensa el siguiente paso por tu cuenta y luego ábrelo para comparar.

Ahora las tres sucursales a la vez

¿En qué mes pasó cada sucursal la mitad de sus ventas del año? Esta vez sin WHERE: las 35 filas en una sola consulta, como en un reporte de verdad. Contesta la pregunta de abajo y escribe la consulta. Si tu porcentaje no llega a 100 en diciembre, pregúntale a tu Maestro.

Comprueba lo que sabes: Sin WHERE, el numerador es SUM(ventas) OVER (PARTITION BY sucursal ORDER BY mes). ¿Qué va en el denominador para que cada sucursal llegue a 100 en diciembre?

Regresa sucursal, mes, ventas, acumulado (dentro de su sucursal) y pctacumulado: el acumulado entre el total del año de su sucursal, por 100, con ROUND(..., 1). Sin WHERE: las 35 filas. Ordena por sucursal, mes. Terminaste cuando diciembre dice 100 en las tres sucursales y julio

Tu turno

Regresa sucursal, mes, ventas, acumulado (dentro de su sucursal) y pct_acumulado: el acumulado entre el total del año de su sucursal, por 100, con ROUND(..., 1). Sin WHERE: las 35 filas. Ordena por sucursal, mes. Terminaste cuando diciembre dice 100 en las tres sucursales y julio de Centro dice 56.2.

Tablas: ventas_mensuales (sucursal, mes, ventas)

ventas_mensuales · 35 filas

ColumnaTipo
sucursal Nombre de la sucursal: Centro, Norte o Sur.VARCHAR
mes Primer día del mes que resume la fila.DATE
ventas Ventas del mes, en pesos.BIGINT

Primeras filas

sucursalmesventas
Centro2025-01-01165100
Centro2025-02-01155700
Centro2025-03-01178700

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ú

En la corrida, Centro iba en 48.2 a junio y en 56.2 a julio, y Norte en 48.3 y 56.1. Sur no tiene junio: llegó a mayo con 43.2 y a julio con 52.3. Las tres pasaron la mitad de su año en julio. Fíjate en que las dos ventanas tienen el mismo PARTITION BY sucursal y solo el numerador tiene ORDER BY: la misma partición, con marcos distintos.

En entrevistas la piden de muchas formas: "calcula el ingreso acumulado de cada usuario por día", "¿en qué fecha cada cliente llegó a 10,000 pesos de compras?" o "¿qué productos suman el 80% de las ventas?". Las tres son una suma acumulada con la partición y el orden correctos. La última ordena de mayor a menor venta y corta donde el porcentaje acumulado pasa de 80. Si quieres practicar la del 80%, pídele a tu Maestro que te la plantee con estos datos.

Si tu reporte mensual tiene una columna "en lo que va del año" que alguien llena a mano o con una fórmula arrastrada, es una línea de SQL. Agrega también el porcentaje del año y revisa con quien lo lee si un mes vacío debe aparecer como fila.

Comprueba lo que sabes: Le quitas ORDER BY mes a SUM(ventas) OVER (PARTITION BY sucursal ORDER BY mes). ¿Qué muestra ahora la columna acumulado?