web-dev-qa-db-ja.com

PostgreSQLでの累積合計の計算

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

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を使用してこの結果を達成したいと思います。

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

58
Yousuf Sultan

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

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

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;

そして、noGROUP BYここに。

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

デフォルトのフレーミングオプションはRANGE UNBOUNDED PRECEDINGで、RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWと同じです。 ORDER BYを使用すると、フレームをに設定します。パーティションのすべての行は、現在の行の最後のORDER BY peerから始まります。

...これは、累積または現在の合計です。大胆な強調鉱山。

同じ(circle_id, ea_year, ea_month)を持つ行は、このクエリでは "peers"です。これらはすべて、合計にすべてのピアが追加された同じ実行中の合計を示します。しかし、テーブルが(circle_id, ea_year, ea_month)UNIQUEであると仮定すると、ソート順序は決定的であり、行にピアはありません。

現在、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;
95