【问题标题】:SQL window function with a where clause?带有 where 子句的 SQL 窗口函数?
【发布时间】:2017-01-15 15:43:33
【问题描述】:

我正在尝试为用户关联两种类型的事件。我想在“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    |

想要的结果:

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

【问题讨论】:

    标签: sql postgresql window-functions


    【解决方案1】:

    刚刚使用 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';
    

    已验证这适用于 PostgreSQL 9.5.4。

    感谢 Gordon 的 FILTER 技巧!

    【讨论】:

    • max()ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 替换lag() 来避免psql FILTER is not implemented for non-aggregate window functions 的绝妙技巧!!
    • 这太酷了。效果很好而且速度很快。感谢分享!
    【解决方案2】:

    这里不需要窗口函数。只需找到所有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(我用过两次)。

    【讨论】:

    • 与使用 lag() 函数的查询相比,此查询的性能如何?
    • 正如 Gordon 所说,这种方法可能更快。
    猜你喜欢
    • 2014-03-26
    • 2020-11-29
    • 1970-01-01
    • 2012-03-25
    • 2012-12-09
    • 2020-09-04
    • 2015-08-17
    • 1970-01-01
    • 2012-07-03
    相关资源
    最近更新 更多