带有where子句的SQL窗口函数?

时间:2016-09-07 20:33:42

标签: sql postgresql window-functions

我试图为用户关联两种类型的事件。我希望看到所有活动" B"以及最近的活动" A"对于该用户之前的" A"事件。如何实现这一目标?特别是,我试图在Postgres中这样做。

我希望有可能使用"其中"窗口函数中的子句,在这种情况下我基本上可以使用"其中event =' A'""""""""'

有什么建议吗?

数据示例:

|user |time|event|
|-----|----|-----|
|Alice|1   |A    |
|Bob  |2   |A    |
|Alice|3   |A    |
|Alice|4   |B    |
|Bob  |5   |B    |
|Alice|6   |B    |

期望的结果:

|user |event_b_time|last_event_a_time|
|-----|------------|-----------------|
|Alice|4           |3                |
|Bob  |5           |2                |
|Alice|6           |3                |

3 个答案:

答案 0 :(得分:15)

使用PostgreSQL 9.5.4尝试了Gordon的方法,它抱怨

  

未对非聚合窗口函数实施FILTER

这意味着不允许将lag()FILTER一起使用。所以我使用max(),一个不同的窗口框架和CTE修改了戈登的查询:

WITH subq AS (
  SELECT
    "user", event, time as event_b_time,
    max(time) FILTER (WHERE event = 'A') OVER (
      PARTITION BY "user"
      ORDER BY time
      ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
    ) AS last_event_a_time
  FROM events
  ORDER BY time
)
SELECT
  "user", event_b_time, last_event_a_time
FROM subq
WHERE event = 'B';

已验证这适用于PostgreSQL 9.5.4。

感谢Gordon的FILTER技巧!

答案 1 :(得分:4)

这是一种方法:

select t.*
from (select t.*,
             lag(time) filter (where event = 'A') (partition by user order by time)
      from t
     ) t
where event = 'B';

相关子查询/横向连接可能具有更好的性能。

答案 2 :(得分:1)

此处不需要窗口功能。只需找到所有B个事件,并为每个事件通过子查询找到同一用户的最新A。这样的事情应该这样做:

SELECT
    "user",
    time AS event_b_time,
    (SELECT time AS last_event_a_time
     FROM t t1
     WHERE "user"=t.user AND event='A' AND time<t.time
     ORDER BY time DESC LIMIT 1)
FROM t
WHERE event='B';

我假设该表名为t(我使用了两次)。