Quiero encontrar la cantidad acumulada o en ejecución de campo e insertarla desde la etapa de preparación a la tabla. Mi estructura de puesta en escena es algo como esto:
ea_month id amount ea_year circle_id
April 92570 1000 2014 1
April 92571 3000 2014 2
April 92572 2000 2014 3
March 92573 3000 2014 1
March 92574 2500 2014 2
March 92575 3750 2014 3
February 92576 2000 2014 1
February 92577 2500 2014 2
February 92578 1450 2014 3
Quiero que mi tabla de destino se vea así:
ea_month id amount ea_year circle_id cum_amt
February 92576 1000 2014 1 1000
March 92573 3000 2014 1 4000
April 92570 2000 2014 1 6000
February 92577 3000 2014 2 3000
March 92574 2500 2014 2 5500
April 92571 3750 2014 2 9250
February 92578 2000 2014 3 2000
March 92575 2500 2014 3 4500
April 92572 1450 2014 3 5950
Realmente estoy muy confundido con la forma de lograr este resultado. Quiero lograr este resultado usando PostgreSQL.
¿Alguien puede sugerir cómo lograr este conjunto de resultados?
sql
postgresql
window-functions
analytic-functions
cumulative-sum
Yousuf Sultan
fuente
fuente
Respuestas:
Básicamente, necesitas una función de ventana . Esa es una característica estándar hoy en día. Además de las funciones de ventana genuinas, puede usar cualquier función agregada como función de ventana en Postgres agregando una
OVER
cláusula.La dificultad especial aquí es conseguir particiones y ordenar correctamente:
SELECT ea_month, id, amount, ea_year, circle_id , sum(amount) OVER (PARTITION BY circle_id ORDER BY ea_year, ea_month) AS cum_amt FROM tbl ORDER BY circle_id, month;
Y hay
GROUP BY
.La suma de cada fila se calcula desde la primera fila de la partición hasta la fila actual, o citando el manual para ser precisos:
... que es la suma acumulada o corriente que busca. El énfasis audaz es mío.
Las filas con lo mismo
(circle_id, ea_year, ea_month)
son "pares" en esta consulta. Todos ellos muestran la misma suma acumulada con todos los pares agregados a la suma. Pero supongo que su tabla estáUNIQUE
activada(circle_id, ea_year, ea_month)
, entonces el orden de clasificación es determinista y ninguna fila tiene pares.Ahora,
ORDER BY ... ea_month
no funcionará con cadenas para nombres de meses. . Postgres ordenaría alfabéticamente según la configuración regional.Si tiene
date
valores reales almacenados en su tabla, puede ordenarlos correctamente. Si no es así, sugiero reemplazarea_year
yea_month
con una sola columnamon
de tipodate
en su tabla.Transforma lo que tienes con
to_date()
:Para la visualización, puede obtener cadenas originales con
to_char()
:Mientras se queda con el desafortunado diseño, esto funcionará:
SELECT ea_month, id, amount, ea_year, circle_id , sum(amount) OVER (PARTITION BY circle_id ORDER BY mon) AS cum_amt FROM (SELECT *, to_date(ea_year || ea_month, 'YYYYMonth') AS mon FROM tbl) ORDER BY circle_id, mon;
fuente
range unbounded preceding
es lo mismo querange between unbounded preceding and current row
. Es por eso quesum()
cuando se usa como una función de ventana produce un total acumulado, mientras que otras funciones de ventana no tienen este marco predeterminado.PARTITION
no siempre se necesita para crear un total acumulado