web-dev-qa-db-ja.com

累積合計に基づくデータのグループ化

私はオンラインで答えを探していましたが、私が達成したいことを正しく定式化する方法と、それが可能かどうか本当にわかりません。 Postgresqlを使用しています。

1日あたりの価格データがあります。

_CREATE TEMP TABLE Price (id,Day, Price) AS 
VALUES
  (1, 1, 40),
  (2, 1, 20),
  (3, 1, 50),
  (4, 1, 10),
  (5, 1, 20),
  (6, 1, 60),
  (7, 2, 10),
  (8, 2, 40),
  (9, 2, 10),
  (10,2, 20),
  (11,2, 10);
_

日と価格の合計に基づいて、数値(1、2、3 ...)を価格データに割り当てます。合計が60を超えるたびに、合計の計算が再開されます。新しい日になると、合計の計算が再開されます。だから例えば:

行1 [日1、価格40] =1。行2 [日1、価格20]の場合、価格の合計は20 + 40 <61なので、行2も1に割り当てられます。 price 50]価格の合計は20 + 40 + 50> 60であるため、合計のカウントを再開する必要があり、番号2が行3に割り当てられます。結果は次のようになります。

enter image description here

これが達成可能かどうか、そしてその方法を誰かが知っていますか? SUM(Price) OVER (PARTITION BY Day ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)の取得方法は理解していますが、条件が満たされたときに合計カウントを再開する方法がわかりません。よろしくお願いします!

6
Nina

あなたはこのようなものが欲しい、

_SELECT *, lag(cumsum,1,0::bigint) OVER (PARTITION BY day ORDER BY id)/60 AS grp
FROM (
  SELECT
    id,
    day,
    price,
    sum(price) OVER (PARTITION BY day ORDER BY id) AS cumsum
  FROM price
) AS t;
_

裏返しにして、ウィンドウ関数でsum()を使用して累積合計を計算します。

_SELECT
  id,
  day,
  price,
  sum(price) OVER (PARTITION BY day ORDER BY id) AS cumsum
FROM price;

 id | day | price | cumsum 
----+-----+-------+--------
  1 |   1 |    40 |     40
  2 |   1 |    20 |     60
  3 |   1 |    50 |    110
  4 |   1 |    10 |    120
  5 |   1 |    20 |    140
  6 |   1 |    60 |    200
  7 |   2 |    10 |     10
  8 |   2 |    40 |     50
  9 |   2 |    10 |     60
 10 |   2 |    20 |     80
 11 |   2 |    10 |     90
(11 rows)
_

cumsumは新しい日にリセットされますが、_60_を過ぎても保持されます。これを修正する必要があります。前の行を見て、60で除算するだけです。last行が60の倍数を超えない限り、新しいグループを開始したくありません。

_SELECT *, lag(cumsum,1,0::bigint) OVER (PARTITION BY day ORDER BY id)/60 AS grp
FROM (
  SELECT
    id,
    day,
    price,
    sum(price) OVER (PARTITION BY day ORDER BY id) AS cumsum
  FROM price
) AS t;
 id | day | price | cumsum | grp 
----+-----+-------+--------+-----
  1 |   1 |    40 |     40 |   0
  2 |   1 |    20 |     60 |   0
  3 |   1 |    50 |    110 |   1
  4 |   1 |    10 |    120 |   1
  5 |   1 |    20 |    140 |   2
  6 |   1 |    60 |    200 |   2
  7 |   2 |    10 |     10 |   0
  8 |   2 |    40 |     50 |   0
  9 |   2 |    10 |     60 |   0
 10 |   2 |    20 |     80 |   1
 11 |   2 |    10 |     90 |   1
(11 rows)
_

これで完了です。

2
Evan Carroll