【问题标题】:Computing session start and end using SQL window functions使用 SQL 窗口函数计算会话开始和结束
【发布时间】:2021-12-15 05:11:30
【问题描述】:

我有一个包含handDate 的游戏日志表,如下所示:

ID handDate
1 2019-06-30 16:14:02.000
2 2019-07-12 06:18:02.000
3 ...

我想根据这个表计算游戏会话(开始和结束),因为:

  • 如果 1 小时后没有任何活动,则会考虑新会话。
  • 一个会话可以存在 2 天

所以我想要这样的结果:

day session_start sesssion_end
2019-06-30 2019-06-15 16:14:02.000 2019-06-15 16:54:02.000
2019-07-02 2019-07-02 16:18:02.000 2019-07-02 17:18:02.000
2019-07-02 2019-07-02 23:18:02.000 2019-07-03 03:18:02.000
2019-07-03 2019-07-03 06:18:02.000 2019-07-03 08:28:02.000

目前我正在使用以下代码,但无法实现我想要的:

SELECT *
             
    FROM (
        SELECT *,
         strftime( '%s', handDate)  - strftime( '%s', prev_event) AS inactivity
                 
        FROM (
            SELECT handDate,
                date( handDate) as day,
                FIRST_VALUE( handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate) AS first_event,
                MIN(handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate),
                MAX(handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate),
                LAG( handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS prev_event,
                LEAD( handDate) OVER (PARTITION BY date( handDate) ORDER BY handDate) AS next_event

                FROM hands
        ) last
    ) final

我正在使用 SQLite

【问题讨论】:

    标签: sql sqlite


    【解决方案1】:
    DROP TABLE IF EXISTS hands;
    
    CREATE TABLE hands(handDate TIMESTAMP);
    
    INSERT INTO hands(handDate)
    VALUES ('2021-10-29 10:30:00')
     , ('2021-10-29 11:35:00')
     , ('2021-10-29 11:36:00')
     , ('2021-10-29 11:37:00')
     , ('2021-10-29 12:38:00')
     , ('2021-10-29 12:39:00')
     , ('2021-10-29 12:39:10')
    ;
    SELECT start_period, end_period
    FROM (
      SELECT is_start, handDate AS start_period
          , CASE WHEN is_start AND is_end THEN handDate
              ELSE LEAD(handDate) OVER (ORDER BY handDate) 
              END AS END_period
      FROM (
        SELECT *
        FROM (
          SELECT *
            ,CASE WHEN (event-prev_event) * 1440.0 > 60 OR prev_event IS NULL THEN true ELSE FALSE END AS is_start
            ,CASE WHEN (next_event-event) * 1440.0 > 60 OR next_event IS NULL THEN true ELSE FALSE END AS is_end
          FROM (
            SELECT handDate
                , juliANDay(handDate) event
                , juliANDay(LAG(handDate) OVER (ORDER BY handDate)) AS prev_event
                , juliANDay(LEAD(handDate) OVER (ORDER BY handDate)) AS next_event
            FROM hands
          ) t
        ) t
        WHERE is_start OR is_end
      )t
    )t
    WHERE is_start
    

    【讨论】:

    • 我看不出它有什么帮助,你只是复制/粘贴了我自己的代码
    • @Matt 我按错了提交。对不起。现在我修复了查询。
    【解决方案2】:

    我找到了以下解决方案:

    SELECT day,
      sessionId,
      MIN(handDate) as sessionStart,
      MAX(handDate) as sessionEnd
    FROM(
          SELECT day,
              handDate,
              sum(is_new_session) over (
                  order by handDate rows between unbounded preceding and current row
              ) as sessionId
          FROM (
                  SELECT *,
                      CASE
                          WHEN prev_event IS NULL
                          OR strftime('%s', handDate) - strftime('%s', prev_event) > 3600 THEN true
                          ELSE false
                      END AS is_new_session
                  FROM (
                          SELECT handDate,
                              date(handDate) as day,
                              LAG(handDate) OVER (
                                  PARTITION BY date(handDate)
                                  ORDER BY handDate RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
                              ) AS prev_event
                          FROM hands
                      )
              )
      )
    GROUP BY sessionId
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-06
      • 2018-05-30
      • 2017-01-18
      • 2015-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多