Basicamente, você precisa de uma função de janela. Essa é uma característica padrão hoje em dia. Além das funções de janela genuínas, você pode usar qualquer função agregada como função de janela no Postgres anexando um
OVER cláusula. A dificuldade especial aqui é obter partições e ordenar corretamente:
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 da primeira linha na partição até a linha atual - ou citando o manual para ser mais preciso:
A opção de enquadramento padrão éRANGE UNBOUNDED PRECEDING, que é o mesmo queRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. ComORDER BY, isso define o quadro como todas as linhas da partição iniciam até o últimoORDER BYda linha atual colega .
... que é a soma acumulada ou corrente que você procura. Minha ênfase em negrito.
Linhas com o mesmo
(circle_id, ea_year, ea_month) são "pares" nesta consulta. Todos eles mostram a mesma soma corrente com todos os pares adicionados à soma. Mas suponho que sua tabela seja UNIQUE em (circle_id, ea_year, ea_month) , a ordem de classificação será determinística e nenhuma linha terá pares. Postgres 11 adicionou ferramentas para incluir/excluir peers com o novo
frame_exclusion opções. Ver:- Agregando todos os valores que não estão no mesmo grupo
Agora,
ORDER BY ... ea_month não funcionará com strings para nomes de meses . O Postgres classificaria em ordem alfabética de acordo com a configuração de localidade. Se você tiver
date real valores armazenados em sua tabela você pode classificar corretamente. Caso contrário, sugiro substituir ea_year e ea_month com uma única coluna mon do tipo date na sua mesa. -
Transforme o que você tem comto_date():
to_date(ea_year || ea_month , 'YYYYMonth') AS mon -
Para exibição, você pode obter strings originais comto_char():
to_char(mon, 'Month') AS ea_month to_char(mon, 'YYYY') AS ea_year
Enquanto estiver preso ao 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;