窗口运行功能,当前行除外

时间:2016-03-09 22:43:43

标签: sql postgresql postgresql-9.5

我有一个理论问题,所以我对替代解决方案不感兴趣。遗憾。

问:是否可以让窗口运行所有先前行的函数值,除了当前的行?

例如:

with
  t(i,x,y) as (
    values
      (1,1,1),(2,1,3),(3,1,2),
      (4,2,4),(5,2,2),(6,2,8)
    )
select
  t.*,
  sum(y) over (partition by x order by i) - y as sum,
  max(y) over (partition by x order by i) as max,
  count(*) filter (where y > 2) over (partition by x order by i) as cnt
from
  t;

实际结果是

 i | x | y | sum | max | cnt 
---+---+---+-----+-----+-----
 1 | 1 | 1 |   0 |   1 |   0
 2 | 1 | 3 |   1 |   3 |   1
 3 | 1 | 2 |   4 |   3 |   1
 4 | 2 | 4 |   0 |   4 |   1
 5 | 2 | 2 |   4 |   4 |   1
 6 | 2 | 8 |   6 |   8 |   2
(6 rows)

我希望maxcnt列的行为类似于sum列,因此,结果应为:

 i | x | y | sum | max | cnt 
---+---+---+-----+-----+-----
 1 | 1 | 1 |   0 |     |   0
 2 | 1 | 3 |   1 |   1 |   0
 3 | 1 | 2 |   4 |   3 |   1
 4 | 2 | 4 |   0 |     |   0
 5 | 2 | 2 |   4 |   4 |   1
 6 | 2 | 8 |   6 |   4 |   1
(6 rows)

可以使用像

这样的简单子查询来实现
select t.*, lag(y,1) over (partition by x order by i) as yy from t

但是是否可以仅使用窗口函数语法,而不使用子查询?

1 个答案:

答案 0 :(得分:2)

是的,你可以。这就是诀窍:

with
  t(i,x,y) as (
    values
      (1,1,1),(2,1,3),(3,1,2),
      (4,2,4),(5,2,2),(6,2,8)
    )
select
  t.*,
  sum(y) over w as sum,
  max(y) over w as max,
  count(*) filter (where y > 2) over w as cnt
from t
window w as (partition by x order by i
             rows between unbounded preceding and 1 preceding);

frame_clause仅选择您感兴趣的窗口框中的那些行。

请注意,在sum列中,由于frame子句,您将获得null而不是0:框架中的第一行没有行。如果需要,你可以coalesce()离开。

SQLFiddle