【问题标题】:How to rank event times by a given time window using SQL?如何使用 SQL 按给定时间窗口对事件时间进行排名?
【发布时间】:2020-05-12 23:12:21
【问题描述】:

我正在努力寻找一种使用 SQL 对事件进行排名的方法。 目标是每当事件发生的时间超过前一次观察的delta 秒(例如 1 秒)时增加排名。到目前为止,我的尝试如下所示:

select a.event_time, a.user_name, a.object_name, a.rnk, case when a.ddif <= 1000 then 0 else 1 end as new_query,
            case when a.ddif <= 1000 then 0 else rnk end as new_rnk
from (
    select *, rank() OVER (PARTITION BY user_name ORDER BY event_time) AS rnk,
              date_diff('second',lag(event_time) OVER (PARTITION BY user_name ORDER BY event_time),event_time) as ddif
    from tmp
    ) a

但它只给了我以下结果,我仍然不知道如何在yellow 中实现结果(它们中的任何一个都非常适合我)。

如果能提供任何帮助,我将不胜感激。

请注意:我使用的是 Presto DB,因此我仅限于这个查询引擎。

【问题讨论】:

    标签: sql window-functions presto gaps-and-islands


    【解决方案1】:

    你可以使用lag()和一个窗口sum()

    select
        t.*,
        sum(case when event_time <= lag_event_time + interval '1' second then 0 else 1 end) rnk 
    from (
        select 
            t.*, 
            lag(event_time) over(order by event_time partition by user_name) lag_event_time
        from mytable t
    ) t
    

    【讨论】:

    • 感谢您的好提示,但是 sum 需要分区或分组,但它为我指明了解决方案的正确方法。
    • @mrjoseph:欢迎。我刚刚在窗口函数中添加了partition 子句。在您的示例数据中,所有行都具有相同的 user_nameobject_name 并不明显
    【解决方案2】:

    感谢所有为我指明最终解决方案方向的好技巧:

    select a.*, sum (case when a.ddif <= 1 then 0 else 1 end) over (partition by user_name order by event_time) as acc_rnk
        from (
            select *, date_diff('second',lag(event_time) OVER (PARTITION BY user_name ORDER BY event_time),event_time) as ddif
            from tmp
            ) a
    

    【讨论】:

    • 我在考虑使用 ceilsecond 功能,但看到你有一个解决方案;)
    【解决方案3】:

    使用lag() 和累积总和来定义组。然后分配行号:

    select t.*,
           row_number() over (partition by user_name, grp order by event_time) as seqnum
    from (select t.*,
                 sum(case when prev_et > event_time - interval '1' second
                          then 0 else 1
                     end) over (partition by user_name order by event_time) as grp
          from (select t.*,
                       lag(event_time) over (partition by user_name order by event_time) as prev_et
                from tmp t
               ) t
         ) t;
    

    【讨论】:

    • 谢谢!它非常接近我在下面分享的最终工作解决方案(以便其他 Presto 用户可以复制它)。
    • @mrjoseph 。 . .我认为直接比较时间戳比date_diff() 更好。我认为该函数返回“边界”的数量,因此“1”的值可能是 0.1 秒或 1.9 秒。
    • 我想你是对的 - 请注意,在 presto 中,间隔的语法有点不同,应该是:间隔 '1' 秒,但其余的都很好,谢谢!顺便提一句。在我的情况下 date_diff 应该可以工作,因为我没有时间戳的毫秒部分
    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    相关资源
    最近更新 更多