PostgreSQLでの累積合計の計算


87

フィールドの累積量または実行量を見つけて、ステージングからテーブルに挿入したいと思います。私のステージング構造は次のようなものです。

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          

ターゲットテーブルを次のようにしたいと思います。

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

私はこの結果を達成する方法について本当に非常に混乱しています。PostgreSQLを使用してこの結果を達成したいと思います。

誰かがこの結果セットを達成する方法を提案できますか?


1
ターゲットテーブルでcum_amountの1000を取得するにはどうすればよいですか?CIRCLE_IDについて、量は2000年のようです

回答:


132

基本的に、ウィンドウ関数が必要です。これは最近の標準機能です。本物のウィンドウ関数に加えて、句を追加することで、Postgresのウィンドウ関数として任意の集計関数を使用できますOVER

ここでの特別な難しさは、パーティションを取得して順序を正しく並べ替えることです。

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;

そして、いいえ GROUP BY

各行の合計は、パーティションの最初の行から現在の行まで計算されます。正​​確には、マニュアルを引用します

デフォルトのフレーミングオプションはRANGE UNBOUNDED PRECEDINGRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWです。これは。と同じです。を使用 ORDER BYすると、フレームは、パーティションの起動から現在の行の最後のORDER BYピアまでのすべての行になるように設定されます。

...これはあなたが求めている累積または現在の合計です。大胆な強調鉱山。

同じ持つ行が(circle_id, ea_year, ea_month)ある「ピア」このクエリインチ これらはすべて同じ実行合計を示し、すべてのピアが合計に追加されます。ただし、テーブルがUNIQUEオンになっていると仮定すると(circle_id, ea_year, ea_month)、並べ替え順序は決定論的であり、ピアを持つ行はありません。

現在、ORDER BY ... ea_month 月名の文字列では機能しません。Postgresは、ロケール設定に従ってアルファベット順にソートします。

dateテーブルに実際の値が格納されている場合は、適切に並べ替えることができます。そうでない場合、私は交換することを提案ea_yearし、ea_month単一の列とmonタイプのdateあなたのテーブルインチ

  • あなたが持っているものを変えるto_date()

      to_date(ea_year || ea_month , 'YYYYMonth') AS mon
    
  • 表示のために、次のコマンドで元の文字列を取得できますto_char()

      to_char(mon, 'Month') AS ea_month
      to_char(mon, 'YYYY') AS ea_year
    

不幸なデザインに固執している間、これはうまくいくでしょう:

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;

解決策をありがとう..もう1つ手伝ってくれませんか。カーソルを使用して同じことを実装したいと思います。ロジックは、すべての円が1年の月に1つのレコードしか持たないというものです。また、この関数は月に1回実行されることになっています。どうすればこれを達成できますか?
Yousuf Sultan

4
@YousufSultan:ほとんどの場合、カーソルよりも優れた解決策があります。それは間違いなく新しい質問のためのものです。新しい質問を始めてください。
Erwin Brandstetter 2014

私はこの答えが不完全であることに気づきましたが、少なくともここで「フレーミング」が行われていることに注意する必要があります。range unbounded precedingこれはデフォルトで、と同じrange between unbounded preceding and current rowです。これがsum()、ウィンドウ関数として使用すると現在の合計が生成される理由ですが、他のウィンドウ関数にはこのデフォルトのフレームがありません。
Hart

1
@ Colin'tHart:明確にするために上記にいくつか追加しました。
Erwin Brandstetter 2016年

より単純なクエリを使用した同様の質問へのリンクPARTITIONは次のとおりです(現在の合計を作成するために常に必要なわけではありません):stackoverflow.com/a/5700744/175830
Jason Axelson 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.