如何根据另一个事件的时间戳顺序找到最近的事件

问题描述

我有一张应用程序事件数据表。每行都有一个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时间戳记。换句话说,我要将上面的表转换成下面的表

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事件分成两个表,并对user_id和page_id进行LEFT JOIN,如下所示,但是当然不起作用,因为它使按钮点击与所有page_opens相匹配该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
;

我是第一次使用这样的事件数据。您可以提供的任何帮助都会很棒。解决此问题的正确方法是什么?

解决方法

这是一个空白问题。您需要定义以“页面打开”事件开始的相邻记录的组。我建议您计算窗口数:

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'

您没有告诉您正在运行哪个数据库。这使用标准的窗口函数语法,并且应在所有支持窗口函数的数据库中工作。

Demo on DB Fiddle

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          
,

查找出现在页面之前的最大page_open时间戳 button_click时间戳。

改为查看下一行是否为单击按钮
您没有标记DBMS,但是大多数系统都支持滞后/领先:

render(){
    //entities is obviously a long list
    var entities = ["a","b","c",...];
    return (
        <div id= "someid" >
            <Input type="select" onChange = { this.props.filterSelect } >
                {
                    entities.map(e => <option>{ e } < /option>)
                }
            < /Input>
        < /div>
    )
}

请参见fiddle