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

MJ.*_*MJ. 12 sql postgresql window-functions

我正在尝试为用户关联两种类型的事件.我希望在"A"事件之前看到所有事件"B"以及该用户的最新事件"A".如何实现这一目标?特别是,我正试图在Postgres中做到这一点.

我希望在窗口函数中可以使用"where"子句,在这种情况下,我基本上可以使用"where event ='A'"来执行LAG(),但这似乎不可能.

有什么建议?

数据示例:

|user |time|event|
|-----|----|-----|
|Alice|1   |A    |
|Bob  |2   |A    |
|Alice|3   |A    |
|Alice|4   |B    |
|Bob  |5   |B    |
|Alice|6   |B    |
Run Code Online (Sandbox Code Playgroud)

期望的结果:

|user |event_b_time|last_event_a_time|
|-----|------------|-----------------|
|Alice|4           |3                |
|Bob  |5           |2                |
|Alice|6           |3                |
Run Code Online (Sandbox Code Playgroud)

Che*_*ian 17

刚试过使用PostgreSQL 9.5.4的Gordon的方法,它抱怨说

对于非聚合窗口函数,未实现FILTER

这意味着使用lag()FILTER是不允许的.所以我使用max()不同的窗口框架和CTE 修改了Gordon的查询:

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';
Run Code Online (Sandbox Code Playgroud)

验证这适用于PostgreSQL 9.5.4.

感谢戈登的FILTER伎俩!


Gor*_*off 5

这是一种方法:

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

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


red*_*neb 4

这里不需要窗口函数。只需查找所有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';
Run Code Online (Sandbox Code Playgroud)

我假设该表已被调用t(我使用了两次)。