Imagina esto: estás siguiendo los ingresos de tu empresa, las ventas en tu tienda online o simplemente analizando tus propios gastos durante el año. No solo necesitas ver los ingresos o gastos de cada mes, sino también entender cómo se van acumulando de mes a mes.
Las funciones agregadas normales (GROUP BY) no nos sirven aquí — agrupan los datos y devuelven una fila por grupo. Pero, ¿qué pasa si queremos ver cada mes y además calcular la suma acumulada? Aquí es donde SUM() junto con funciones de ventana nos salva la vida.
Bases del uso de funciones de ventana para sumas acumuladas
Las funciones de ventana te permiten hacer operaciones agregadas sobre ventanas de datos. Así, por ejemplo, puedes sumar valores en cada fila, pero sin eliminar las demás filas. ¡No más sacrificios por culpa de GROUP BY!
Sintaxis de SUM() con función de ventana
Aquí tienes la plantilla básica para usar la suma acumulada:
SELECT
column_name,
SUM(column_name) OVER (PARTITION BY partition_column ORDER BY order_column) AS cumulative_sum
FROM
table_name;
En este caso:
SUM(column_name)— suma los valores.OVER()— define la ventana para el cálculo.PARTITION BY— divide los datos en grupos (opcional).ORDER BY— define el orden de las filas dentro de la ventana.
Ejemplo: ingresos acumulados por meses
Imagina una tabla con tus ingresos:
| mes | ingreso |
|---|---|
| 2023-01 | 1000 |
| 2023-02 | 1500 |
| 2023-03 | 2000 |
Queremos ver el ingreso de cada mes y el acumulado. Vamos a escribir la consulta SQL:
SELECT
mes,
ingreso,
SUM(ingreso) OVER (ORDER BY mes) AS ingreso_acumulado
FROM
ingresos;
Resultado:
| mes | ingreso | ingreso_acumulado |
|---|---|---|
| 2023-01 | 1000 | 1000 |
| 2023-02 | 1500 | 2500 |
| 2023-03 | 2000 | 4500 |
¿Qué está pasando aquí?
ORDER BY mesdentro deOVER()le dice a PostgreSQL que las filas deben considerarse en orden cronológico.- Para cada fila, la suma se calcula teniendo en cuenta todas las filas anteriores (y la actual).
Piénsalo bien: para la primera fila, SUM() suma solo la primera fila, para la segunda — suma dos filas, para la tercera — suma tres filas. ¡Por eso el orden de los meses es tan importante!
Ejemplo: ingresos acumulados por regiones
Si tuvieras una tabla de ventas por regiones, una parte podría verse así:
| región | mes | ingreso |
|---|---|---|
| Norte | 2023-01 | 1000 |
| Norte | 2023-02 | 1500 |
| Sur | 2023-01 | 2000 |
| Sur | 2023-02 | 2500 |
Ahora queremos calcular el ingreso acumulado por cada región:
SELECT
región,
mes,
ingreso,
SUM(ingreso) OVER (PARTITION BY región ORDER BY mes) AS ingreso_acumulado
FROM
ventas;
El resultado será así:
| región | mes | ingreso | ingreso_acumulado |
|---|---|---|---|
| Norte | 2023-01 | 1000 | 1000 |
| Norte | 2023-02 | 1500 | 2500 |
| Sur | 2023-01 | 2000 | 2000 |
| Sur | 2023-02 | 2500 | 4500 |
Ahora cada región se analiza por separado (PARTITION BY región), pero dentro de cada región las filas se ordenan por tiempo (ORDER BY mes).
Media móvil (AVG())
Vale, las sumas acumuladas están geniales, pero ¿y si quieres analizar tendencias, por ejemplo, de los últimos 3 meses? Para eso sirve la media móvil.
Ejemplo: media móvil de ingresos
Seguimos trabajando con la tabla ingresos, y aquí están sus datos:
| mes | ingreso |
|---|---|
| 2023-01 | 1000 |
| 2023-02 | 1500 |
| 2023-03 | 2000 |
| 2023-04 | 2500 |
Consulta para calcular la media móvil de 3 meses:
SELECT
mes,
ingreso,
AVG(ingreso) OVER (
ORDER BY mes
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS media_móvil
FROM
ingresos;
Resultado:
| mes | ingreso | media_móvil |
|---|---|---|
| 2023-01 | 1000 | 1000 |
| 2023-02 | 1500 | 1250 |
| 2023-03 | 2000 | 1500 |
| 2023-04 | 2500 | 2000 |
Explicación:
ROWS BETWEEN 2 PRECEDING AND CURRENT ROWle dice a PostgreSQL que mire la fila actual y las dos filas anteriores para calcular la media.- Así, para cada mes vemos el ingreso medio de los últimos 3 meses.
O sea, para cada fila definimos una ventana de 3 filas: la actual y las dos anteriores. Y luego calculamos la media sobre ellas. Súper útil.
Cómo funciona ORDER BY y su importancia
Las funciones de ventana dependen del orden correcto de las filas. Si el orden está mal (o ni siquiera está), los resultados pueden ser raros.
Ejemplo: errores por no usar ORDER BY
Si quitamos ORDER BY de OVER(), en vez de la suma acumulada obtenemos la suma total de todos los ingresos en cada fila:
SELECT
mes,
ingreso,
SUM(ingreso) OVER () AS suma_acumulada_incorrecta
FROM
ingresos;
Resultado:
| mes | ingreso | sumaacumuladaincorrecta |
|---|---|---|
| 2023-01 | 1000 | 7000 |
| 2023-02 | 1500 | 7000 |
| 2023-03 | 2000 | 7000 |
| 2023-04 | 2500 | 7000 |
Las filas no están ordenadas y, en vez de la suma acumulada, la función simplemente suma todo para cada fila sin distinguir nada.
Casos reales de uso
Análisis de ingresos:
- Las sumas acumuladas te permiten seguir cómo crecen las ventas o los ingresos de la empresa.
- La media móvil ayuda a ver la tendencia "limpia" sin tanto ruido.
Modelado financiero:
Bancos y empresas financieras usan funciones de ventana para analizar pagos, crecimiento de deudas y otras métricas.
Análisis de series temporales:
Datos temporales como número de usuarios online, vistas de página, ingresos, etc., se analizan perfecto con SUM() y AVG().
GO TO FULL VERSION