多个窗口函数的累积和

时间:2019-09-10 07:54:10

标签: postgresql

我有一个结构如下的表:


id | date       | player_id | score
--------------------------------------
1  | 2019-01-01 | 1         | 1
2  | 2019-01-02 | 1         | 1
3  | 2019-01-03 | 1         | 0
4  | 2019-01-04 | 1         | 0
5  | 2019-01-05 | 1         | 1
6  | 2019-01-06 | 1         | 1
7  | 2019-01-07 | 1         | 0
8  | 2019-01-08 | 1         | 1
9  | 2019-01-09 | 1         | 0
10 | 2019-01-10 | 1         | 0
11 | 2019-01-11 | 1         | 1

我想再创建两列“ total_score”,“ last_seven_days”。

total_score是player_id得分的滚动总和

last_seven_days是过去7天(包括该日期之前和该日期之前)的得分

我编写了以下SQL查询:

SELECT id,
    date,
    player_id,
    score,
    sum(score) OVER all_scores AS all_score,
    sum(score) OVER last_seven AS last_seven_score
   FROM scores
  WINDOW all_scores AS (PARTITION BY player_id ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 
last_seven AS (PARTITION BY player_id ORDER BY id ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING);

并获得以下输出:


id | date       | player_id | score | all_score | last_seven_score   
------------------------------------------------------------------
1  | 2019-01-01 | 1         | 1     |           | 
2  | 2019-01-02 | 1         | 1     | 1         | 1
3  | 2019-01-03 | 1         | 0     | 2         | 2
4  | 2019-01-04 | 1         | 0     | 2         | 2
5  | 2019-01-05 | 1         | 1     | 2         | 2
6  | 2019-01-06 | 1         | 1     | 3         | 3
7  | 2019-01-07 | 1         | 0     | 4         | 4
8  | 2019-01-08 | 1         | 1     | 4         | 4
9  | 2019-01-09 | 1         | 0     | 5         | 4
10 | 2019-01-10 | 1         | 0     | 5         | 3
11 | 2019-01-11 | 1         | 1     | 5         | 3

我意识到我需要对此进行更改

last_seven AS (PARTITION BY player_id ORDER BY id ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING)

而不是7,而是使用某种日期格式,因为仅使用数字7会导致错误。

即能够做date - 2daysdate - 6days

我还想添加3个月,6个月,12个月之后的列,因此需要它能够保持动态。

DEMO

2 个答案:

答案 0 :(得分:1)

您需要在RANGE之前使用窗口:

last_seven AS (PARTITION BY player_id
               ORDER BY date
               RANGE BETWEEN INTERVAL '7 days' PRECEDING
                         AND INTERVAL '1 day' PRECEDING)

此解决方案仅适用于v11以上版本。

答案 1 :(得分:1)

demo:db<>fiddle


Postgres 11 + 的解决方案:

与@LaurenzAlbe一样使用RANGE interval


Postgres <11 的解决方案:

(仅显示“天”部分,“ all_scores”部分相同)

player_id和相关的date范围内针对自己加入表格:

SELECT s1.*,
    (SELECT SUM(s2.score)
     FROM scores s2
     WHERE s2.player_id = s1.player_id
         AND s2."date" BETWEEN s1."date" - interval '7 days' AND s1."date" - interval '1 days')
FROM scores s1