基于累积总和的数据分组

Nin*_*ina 6 postgresql window-functions gaps-and-islands sum

我一直在网上寻找答案,但真的不知道如何正确地制定我想要实现的目标以及是否可能,如果问题听起来很愚蠢,请抱歉。我正在使用 Postgresql。

我每天都有价格数据。

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);
Run Code Online (Sandbox Code Playgroud)

我想根据日期和价格总和为价格数据分配数字(1、2、3...)。每当总和 > 60 时,总和计算再次开始 + 每次到达新的一天时,总和计算再次开始。例如:

第 1 行 [第 1 天,价格 40] = 1。然后对于第 2 行 [第 1 天,价格 20],价格总和为 20 + 40 < 61,因此第 2 行也被分配给 1。然后对于第 3 行 [第 1 天, price 50] 价格总和是 20 + 40 + 50 > 60,因此总和的计数必须重新开始,数字 2 分配给第 3 行。结果将如下所示:

在此处输入图片说明

有谁知道这是否可以实现以及如何实现?我知道如何取SUM(Price) OVER (PARTITION BY Day ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),但不知道如何在满足条件时重新开始总和计数。预先感谢您的帮助!

Eva*_*oll 2

你想要这样的东西,

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;
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

请注意,我们cumsum在新的一天进行了重置,但它仍然持续到您的60. 我们需要解决这个问题,因为我们只需查看前一行,然后除以 60。我们不想开始一个新组,除非最后一行超过 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)
Run Code Online (Sandbox Code Playgroud)

你就完成了。