Postgresql 中的时间-window 滚动总和

Time-window rolling sum in Postgresql

我想知道是否可以在 Postgresql 中使用 window 基于时间的查询。

原始数据在前三列(日期、业务员、金额):

date salesman amount sum-3-rolling-days
2020-01-01 john 10 10
2020-01-02 john 15 25
2020-01-03 john 8 33
2020-01-04 john 12 35
2020-01-05 john 11 31
2020-01-01 daniel 5 5
2020-01-02 daniel 6 11
2020-01-03 daniel 7 18
2020-01-04 daniel 8 21
2020-01-05 daniel 9 24

第四列表示该销售员在过去三天的总金额。

Pandas 具有执行此操作的内置函数,但我想不出使用内置 sum() over () 语法在 Postgresql 中执行此操作的任何方法。我能够使用的唯一方法是使用横向连接和子查询的复杂组合以及时间增量比较的条件,这至少可以说是不雅的。

Pandas' 方式(根据记忆,确切的语法可能略有不同)——无法得到任何简洁:

df.groupby('salesman').rolling('3d').sum()

demos:db<>fiddle

SELECT
    *,
    SUM(amount) OVER (
        PARTITION BY salesman                     -- 1
        ORDER BY "date"                           -- 2
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW  -- 3
    )
FROM mytable
  1. salesman 构建 groups/partitions。所以,以下只会在个分区
  2. 内完成
  3. date 列排序
  4. 仅对当前日期和当前日期之间的 2 个记录求和。这是滚动部分

如果您使用的是 Postgres 11 或更高版本,您可以使用带日期间隔的 RANGE 更精确地定义 window 而不是计算 ROWS:

SELECT
    *,
    SUM(amount) OVER (
        PARTITION BY salesman                    
        ORDER BY "date"                          
        RANGE BETWEEN interval '2 days' PRECEDING AND CURRENT ROW
    )
FROM mytable

您可以使用CTE(常用table表达式)。 试试

with data as (
select
  date,
  salesman,
  amount
from
  foo
group by
  date,
  salesman
order by
  date,
  salesman,
)

select
  *,
  sum(amount) over (
    partition by salesman order by date,
    salesman rows between unbounded preceding and current row
  ) as rolling
from data;