Desejo encontrar a quantidade cumulativa ou corrente de campo e inseri-la da preparação para a tabela. Minha estrutura de teste é mais ou menos assim:
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
Quero que minha tabela de destino se pareça com isto:
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
Estou realmente muito confuso sobre como proceder para alcançar este resultado. Eu quero alcançar este resultado usando PostgreSQL.
Alguém pode sugerir como proceder para atingir esse conjunto de resultados?
sql
postgresql
window-functions
analytic-functions
cumulative-sum
Yousuf Sultan
fonte
fonte
Respostas:
Basicamente, você precisa de uma função de janela . Esse é um recurso padrão hoje em dia. Além das funções de janela genuínas, você pode usar qualquer função de agregação como função de janela no Postgres anexando uma
OVER
cláusula.A dificuldade especial aqui é obter as partições e a ordem de classificação correta:
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;
E não
GROUP BY
.A soma de cada linha é calculada a partir da primeira linha na partição até a linha atual - ou citando o manual para ser mais preciso:
... que é a soma cumulativa ou contínua que você busca. Ênfase em negrito minha.
Linhas com o mesmo
(circle_id, ea_year, ea_month)
são "pares" nesta consulta. Todos eles mostram a mesma soma contínua com todos os pares adicionados à soma. Mas suponho que sua tabela estejaUNIQUE
ativada(circle_id, ea_year, ea_month)
, então a ordem de classificação é determinística e nenhuma linha tem pares.Agora,
ORDER BY ... ea_month
não funcionará com strings para nomes de meses . Postgres seria classificado em ordem alfabética de acordo com a configuração local.Se você tiver
date
valores reais armazenados em sua tabela, poderá classificar corretamente. Caso contrário, sugiro substituirea_year
eea_month
por uma única colunamon
do tipodate
em sua tabela.Transforme o que você tem com
to_date()
:Para exibição, você pode obter strings originais com
to_char()
:Embora preso com o design infeliz, isso 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;
fonte
range unbounded preceding
é, que é o mesmo querange between unbounded preceding and current row
. É por isso quesum()
quando usado como uma função de janela produz um total em execução - enquanto outras funções de janela não têm esse quadro padrão.PARTITION
nem sempre é necessário para criar um total em execução): stackoverflow.com/a/5700744/175830