Redshift:查找会话中的第一个和最后一个事件而没有任何会话ID

时间:2018-10-02 12:38:31

标签: sql join amazon-redshift self-join

我在移动应用中有一个Redshift用户事件表:

|user|   screen   |collector_timestamp|
---------------------------------------
|1111| StartScreen|2018-10-01 07:02:33|
|1111|FinishScreen|2018-10-01 07:02:34|
|1112| OrderScreen|2018-10-01 07:10:33|
|1113| StartScreen|2018-10-01 09:01:27|

会话-连续事件之间的间隔小于1小时的活动。

我想找到一个会话(第一个和最后一个collector_timestamp),在该会话中,用户访问0个或多个屏幕,然后访问StartScreen,然后访问0个或多个屏幕,然后访问OrderScreen,然后是0个或更多屏幕,然后是FinishScreen

当我尝试应用三重自联接时,permission denied to create temporary tables in database出现错误,因为联接的结果未在内存中触发。

我还能如何找到合适的会话?

1 个答案:

答案 0 :(得分:1)

首先使用Redshift中的LAG窗口函数创建会话ID。 然后,仅使用您关心的屏幕在会话中聚合顺序事件。使用此功能,您可以筛选出所需的确切模式。该示例在一个查询中执行此操作,但实际上可能应使用多个表来完成,因此您可以引用每个会话的详细数据。以下代码使用您提供的数据在Redshift中构建了一个独立的示例,并带有一些其他记录来演示结果。

DROP TABLE IF EXISTS events;
CREATE TABLE events
    ("user" INT
    , "screen" VARCHAR(12)
    , "collector_timestamp" TIMESTAMP
);

INSERT INTO events
    ("user", "screen", "collector_timestamp")
VALUES
    (1111, 'StartScreen', '2018-10-01 07:02:33'),
    (1111, 'FinishScreen', '2018-10-01 07:02:34'),
    (1112, 'OrderScreen', '2018-10-01 07:10:33'),
    (1113, 'StartScreen', '2018-10-01 09:01:27'),
    (1112, 'StartScreen', '2018-10-01 09:10:33'),
    (1112, 'OrderScreen', '2018-10-01 09:11:33'),
    (1112, 'FinishScreen', '2018-10-01 09:12:33')
;

WITH sessionized_events AS(
  SELECT *
    , "user"||'_'|| SUM(new_session) OVER (PARTITION BY USER ORDER BY collector_timestamp ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS session_id
  FROM(
      SELECT 
          *
          , CASE
               WHEN EXTRACT(EPOCH FROM collector_timestamp) 
                       - LAG(EXTRACT(EPOCH FROM collector_timestamp))
                         OVER (PARTITION BY "user" ORDER BY collector_timestamp) >= 60 * 60
              THEN 1
              ELSE 0
            END AS new_session
      FROM events
  ) s
)
SELECT 
    session_id
FROM sessionized_events
GROUP BY 1
HAVING listagg(DISTINCT screen)
        WITHIN GROUP (ORDER BY collector_timestamp) like ('%StartScreen%OrderScreen%FinishScreen')
;

结果:

session_id
----------
1112_1

Postgres的语法与Redshift不同,但是对于没有Redshift集群的语法,我在SQLFiddle here上有一个示例。