SQL - 基于时间线的查询

Posted

技术标签:

【中文标题】SQL - 基于时间线的查询【英文标题】:SQL - timeline based queries 【发布时间】:2020-12-13 11:04:59 【问题描述】:

我有一个事件表,其中有:

user_id 事件名称 event_time

类型有事件名称:meeting_startedmeeting_endedemail_sent

我想创建一个查询来计算会议期间电子邮件的发送次数。

更新:我正在使用 Google BigQuery。

查询示例:

SELECT
event_name,
count(distinct user_id) users,
FROM
events_table WHERE
and event_name IN ('meeting_started', 'meeting_ended')
group by 1

我怎样才能做到这一点? 谢谢!

【问题讨论】:

会议可以重叠吗?如果数据中存在异常情况,例如似乎永远不会结束的会议怎么办? 【参考方案1】:

您可以在 BigQuery 中使用 last_value() 执行此操作:

如果最近的“会议”事件是'meeting_started',则可能会在会议期间发送一封电子邮件。因此,您可以通过获取每个事件的最新会议事件然后过滤来解决此问题:

select et.*
from (select et.*,
             last_value(case when event_name in ('meeting_started', 'meeting_ended') then event_name end) ignore nulls) over
                 (partition by user_id order by event_time) as last_meeting_event
      from events_table et
     ) et
where event_name = 'email_sent' and last_meeting_event = 'meeting_started'

【讨论】:

【参考方案2】:

这看起来像是某种间隙和岛屿问题,其中一个岛屿是一个会议,而您想要属于岛屿的电子邮件。

我们如何定义一个岛屿?假设会议开始和结束正确交错,我们可以按每个用户比较开始和结束的计数。如果开始的次数多于结束的次数,则会议正在进行中。使用此逻辑,您可以获取在会议期间发送的所有电子邮件,如下所示:

select *
from (
    select e.*,
        countif(event_name = 'meeting_started') over(partition by user_id order by event_time) as cnt_started,
        countif(event_name = 'meeting_ended'  ) over(partition by user_id order by event_time) as cnt_ended
    from events_table e
) e
where event_name = 'email_sent' and cnt_started > cnt_ended

目前还不清楚你想从这里去哪里。如果您想计算此类电子邮件的数量,只需在外部查询中使用select count(*) 而不是select *

【讨论】:

以上是关于SQL - 基于时间线的查询的主要内容,如果未能解决你的问题,请参考以下文章

组合 SQL 查询,基于计算连接表

基于纬度/经度查询附近兴趣点的 SQL 查询 - SQLite

基于标签的 SQL 查询

SQL BigQuery:选择基于时间的查询

基于最近时间戳连接两个表的 SQL 查询

基于 Databricks Spark SQL 子查询的查询抛出 TreeNodeException