微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用窗口函数按时间条件计算移动总和/计数并过滤PostgreSQL

如何解决使用窗口函数按时间条件计算移动总和/计数并过滤PostgreSQL

我想在第30天的行中计算前29天的总和,我使用过滤器和窗口函数,但是FILTER不起作用,

如果我使用它,它仍然从头到尾求和:

Select *,Sum(quantity) filter (where time between time - interval '29 day' and time) over ()
from t1 

如果我使用它,则显示空列

Select *,Sum(quantity) filter (where time between time - interval '29 day' and time - interval '1 day') over ()
from t1

数据,为简单起见,我减少了列数

Time        sum_quantity
2020-01-01  1
2020-01-02  2
2020-01-03  3
2020-01-04  6
    ....
2020-01-30  100

数据类型:时间是日期,数量是整数

所需结果: 应该与第一个表格具有相同的列,并添加此移动总和列

第30天=每30天第1天到第29天的总量

如何解决此问题

解决方法

您希望使用带有range的窗框定义的窗函数:

select t1.*,sum(quantity) over (order by time
                           range between interval '29 day' preceding and current row
                          ) 
from t1 ;

编辑:

如果您拥有所有日期的数据,则可以使用rows

select t1.*,sum(quantity) over (order by time
                           rows between 29 preceding and current row
                          ) 
from t1 ;

编辑II:

如果您需要在不支持range的较旧版本的Postgres中处理丢失的日子,那么扩展数据可能是最简单的方法:

select t1.*,sum(quantity) over (order by time
                           rows between 29 preceding and current row
                           ) 
from (select generate_series(min(t1.time),max(t1.time),interval '1 day') as dte
      from t1
     ) d left join
     t1
     on d.dte = t1.time;

您可能要过滤掉其他行:

select t1.*
from (select t1.*,sum(quantity) over (order by time
                                 rows between 29 preceding and current row
                                 ) as running_sum
      from (select generate_series(min(t1.time),interval '1 day') as dte
            from t1
           ) d left join
           t1
           on d.dte = t1.time
     ) t1
where t1.time is not null;
,

您的filter (where)子句始终为true,空over()子句在所有结果集中都是窗口显示的。

您应该在over子句中指定窗口,而不是在filter子句中指定窗口。可能您需要类似

sum(quantity) over (order by time rows between 29 preceding and current row)

或更好的range between...

,

这是您想要的吗?

select m1.Time,(select sum(sum_quantity) 
          from mytable m
          where m.time between (m1.time - interval '29 day') and (m1.time)) sum_total
from mytable m1
group by m1.Time
order by m1.Time;

或者也许更好:

select m1.Time,sum(m.sum_quantity) 
from mytable m
     join mytable m1 on m.time between (m1.time - interval '29 day') and (m1.time)
group by m1.Time
order by m1.Time;

这是一个演示:

DEMO

,

请在易用的地方使用条件,因为您使用的是Windows函数,因此就像条件表达式一样:

SUM(<expression>) FILTER(WHERE <condition>)
SUM(CASE WHEN <condition> THEN <expression> END)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。