如何根据另一个事件的时间戳按顺序查找最近的事件
How do I find the most recent event in sequence based on the timestamp of another event
我有一个 table 的应用程序事件数据。每行都有一个 user_id、一个时间戳、一个 page_id、一个 event_name 和其他字段。我现在关心的事件是 page_open 和 button_click 事件,但还有 10 种其他事件类型可能发生在两者之间,例如滚动。用户可能多次打开同一个页面,但只是偶尔点击页面上的一个按钮,如下例所示。
user_id timestamp page_id event_name
------- ---------- ------- --------------
71 12:00:34 307 page_open
88 13:01:44 307 page_open
71 13:02:09 307 page_open
71 13:02:11 307 scroll
71 13:04:41 307 page_open
71 13:04:42 307 scroll
71 13:04:45 307 button_click_a
71 13:08:30 307 page_open
88 13:09:01 307 button_click_b
对于每个用户的每个 page_open 事件,我想要一个额外的列来告诉我是否最终单击了按钮。我没有要使用的页面“会话”,所以我必须寻找在 button_click 时间戳之前发生的最大 page_open 时间戳。换句话说,我想把上面的table改成下面的table
user_id timestamp page_id event_name button_event
------- ---------- ------- ---------- --------------
71 12:00:34 307 page_open NULL
88 13:01:44 307 page_open button_click_b
71 13:02:09 307 page_open NULL
71 13:04:41 307 page_open button_click_a
71 13:08:30 307 page_open NULL
我试图将 page_open 和 button_click 事件分成两个 table 并在 user_id 和 page_id 上执行 LEFT JOIN
就像您在下面看到的那样,但当然这没有用,因为它匹配按钮点击到所有 page_open 和那个 page_id。我只想将按钮点击与其对应的 page_open 事件相匹配。
SELECT
a.user_id,
a.timestamp,
a.page_id,
a.event_name,
b.event_name AS button_event
FROM
(SELECT * FROM events WHERE event_name = 'page_open') a
LEFT JOIN
(SELECT * FROM events WHERE event_name = 'button_click_a' OR event_name = 'button_click_b') b
ON
a.user_id = b.user_id AND
a.page_id = b.page_id
;
我是处理此类事件数据的新手。你能提供的任何帮助都会很棒。解决这个问题的正确方法是什么?
这是一个 gaps-and-islands 问题。您需要定义以“页面打开”事件开始的相邻记录组;我会推荐 window 计数:
select *
from (
select
t.*,
max(case when event_name <> 'page_open' then event_name end)
over(partition by page_id, user_id, grp) button_event
from (
select
t.*,
sum(case when event_name = 'page_open' then 1 else 0 end)
over(partition by page_id, user_id order by timestamp) grp
from mytable t
where event_name = 'page_open' or event_name like 'button_click_%'
) t
) t
where event_name = 'page_open'
你没有告诉你是哪个数据库运行。这使用标准 window 函数语法,并且应该在所有支持 window 函数的数据库中工作。
user_id | timestamp | page_id | event_name | grp | button_event
------: | :-------- | ------: | :--------- | --: | :-------------
71 | 12:00:34 | 307 | page_open | 1 | null
88 | 13:01:44 | 307 | page_open | 1 | button_click_b
71 | 13:02:09 | 307 | page_open | 2 | null
71 | 13:04:41 | 307 | page_open | 3 | button_click_a
71 | 13:08:30 | 307 | page_open | 4 | null
look for the max page_open timestamp that occurred before the
button_click timestamp.
重新措辞 看看下一行是否是 button-click。
您没有标记 DBMS,但大多数系统支持 Lag/LEAD:
with cte as
(
select
user_id,
timestamp,
page_id,
event_name,
-- find the next non-'page_open' event
lead(case when event_name <> 'page_open'
then event_name
end)
over (partition by user_id
order by timestamp) AS button_event
from mytable
where event_name in ('page_open','button_click_a','button_click_b')
)
select *
from cte
where event_name = 'page_open' -- remove click rows
我有一个 table 的应用程序事件数据。每行都有一个 user_id、一个时间戳、一个 page_id、一个 event_name 和其他字段。我现在关心的事件是 page_open 和 button_click 事件,但还有 10 种其他事件类型可能发生在两者之间,例如滚动。用户可能多次打开同一个页面,但只是偶尔点击页面上的一个按钮,如下例所示。
user_id timestamp page_id event_name
------- ---------- ------- --------------
71 12:00:34 307 page_open
88 13:01:44 307 page_open
71 13:02:09 307 page_open
71 13:02:11 307 scroll
71 13:04:41 307 page_open
71 13:04:42 307 scroll
71 13:04:45 307 button_click_a
71 13:08:30 307 page_open
88 13:09:01 307 button_click_b
对于每个用户的每个 page_open 事件,我想要一个额外的列来告诉我是否最终单击了按钮。我没有要使用的页面“会话”,所以我必须寻找在 button_click 时间戳之前发生的最大 page_open 时间戳。换句话说,我想把上面的table改成下面的table
user_id timestamp page_id event_name button_event
------- ---------- ------- ---------- --------------
71 12:00:34 307 page_open NULL
88 13:01:44 307 page_open button_click_b
71 13:02:09 307 page_open NULL
71 13:04:41 307 page_open button_click_a
71 13:08:30 307 page_open NULL
我试图将 page_open 和 button_click 事件分成两个 table 并在 user_id 和 page_id 上执行 LEFT JOIN
就像您在下面看到的那样,但当然这没有用,因为它匹配按钮点击到所有 page_open 和那个 page_id。我只想将按钮点击与其对应的 page_open 事件相匹配。
SELECT
a.user_id,
a.timestamp,
a.page_id,
a.event_name,
b.event_name AS button_event
FROM
(SELECT * FROM events WHERE event_name = 'page_open') a
LEFT JOIN
(SELECT * FROM events WHERE event_name = 'button_click_a' OR event_name = 'button_click_b') b
ON
a.user_id = b.user_id AND
a.page_id = b.page_id
;
我是处理此类事件数据的新手。你能提供的任何帮助都会很棒。解决这个问题的正确方法是什么?
这是一个 gaps-and-islands 问题。您需要定义以“页面打开”事件开始的相邻记录组;我会推荐 window 计数:
select *
from (
select
t.*,
max(case when event_name <> 'page_open' then event_name end)
over(partition by page_id, user_id, grp) button_event
from (
select
t.*,
sum(case when event_name = 'page_open' then 1 else 0 end)
over(partition by page_id, user_id order by timestamp) grp
from mytable t
where event_name = 'page_open' or event_name like 'button_click_%'
) t
) t
where event_name = 'page_open'
你没有告诉你是哪个数据库运行。这使用标准 window 函数语法,并且应该在所有支持 window 函数的数据库中工作。
user_id | timestamp | page_id | event_name | grp | button_event ------: | :-------- | ------: | :--------- | --: | :------------- 71 | 12:00:34 | 307 | page_open | 1 | null 88 | 13:01:44 | 307 | page_open | 1 | button_click_b 71 | 13:02:09 | 307 | page_open | 2 | null 71 | 13:04:41 | 307 | page_open | 3 | button_click_a 71 | 13:08:30 | 307 | page_open | 4 | null
look for the max page_open timestamp that occurred before the button_click timestamp.
重新措辞 看看下一行是否是 button-click。
您没有标记 DBMS,但大多数系统支持 Lag/LEAD:
with cte as
(
select
user_id,
timestamp,
page_id,
event_name,
-- find the next non-'page_open' event
lead(case when event_name <> 'page_open'
then event_name
end)
over (partition by user_id
order by timestamp) AS button_event
from mytable
where event_name in ('page_open','button_click_a','button_click_b')
)
select *
from cte
where event_name = 'page_open' -- remove click rows