Snowflake基于Partitioning的特定Event记录统计SQL查询求助
问题描述
业务记录结构
| login_id | login_type | login_name | login_timestamp | page_id |
|---|---|---|---|---|
| 1 | event | null | 2023-01-13 00:22:02.560 | 1 |
| 1 | event | null | 2023-01-13 00:22:02.634 | 1 |
| 1 | page | login | 2023-01-13 00:22:02.882 | 1 |
| 1 | event | login | 2023-01-13 00:22:02.929 | 1 |
| 1 | page | login | 2023-01-13 00:22:02.922 | 2 |
| 1 | event | login | 2023-01-13 00:22:02.962 | 2 |
| 1 | event | null | 2023-01-13 00:22:07.751 | 2 |
| 2 | event | null | 2023-01-13 00:24:02.560 | 1 |
| 2 | event | null | 2023-01-13 00:24:02.634 | 1 |
| 2 | page | login | 2023-01-13 00:24:02.882 | 1 |
| 2 | event | null | 2023-01-13 00:24:02.929 | 1 |
| 2 | event | login | 2023-01-13 00:24:02.962 | 1 |
| 2 | event | null | 2023-01-13 00:24:07.751 | 1 |
| 3 | page | login | 2023-01-13 00:26:02.882 | 1 |
| 3 | event | null | 2023-01-13 00:26:02.929 | 1 |
| 3 | page | login | 2023-01-13 00:26:02.949 | 2 |
| 3 | event | login | 2023-01-13 00:26:02.962 | 2 |
| 3 | event | null | 2023-01-13 00:26:07.751 | 2 |
查询需求
- 仅获取
login_name为null且login_type='event'的记录 - 按
login_id、page_id进行分区,根据login_timestamp排序,统计该分区内login_type='page'记录之前和之后的符合条件的event记录数量
示例输出
| login_id | login_type | login_name | count_of_event_before_page | count_of_event_afer_page | page_id |
|---|---|---|---|---|---|
| 1 | event | null | 2 | 0 | 1 |
| 1 | event | null | 0 | 1 | 2 |
| 2 | event | null | 2 | 2 | 1 |
| 3 | event | null | 0 | 1 | 1 |
| 3 | event | null | 0 | 1 | 2 |
解决方案
可以通过窗口函数结合子查询实现需求,Snowflake SQL语句如下:
WITH page_events AS ( -- 提取各分区内page记录的时间戳 SELECT login_id, page_id, login_timestamp AS page_timestamp FROM your_table_name WHERE login_type = 'page' ), qualified_events AS ( -- 筛选符合条件的event记录 SELECT login_id, login_type, login_name, login_timestamp, page_id FROM your_table_name WHERE login_type = 'event' AND login_name IS NULL ), event_counts AS ( -- 计算page记录前后的符合条件event数量 SELECT qe.login_id, qe.login_type, qe.login_name, qe.page_id, -- 统计page记录之前的符合条件event数 SUM(CASE WHEN qe.login_timestamp < pe.page_timestamp THEN 1 ELSE 0 END) OVER (PARTITION BY qe.login_id, qe.page_id) AS count_of_event_before_page, -- 统计page记录之后的符合条件event数 SUM(CASE WHEN qe.login_timestamp > pe.page_timestamp THEN 1 ELSE 0 END) OVER (PARTITION BY qe.login_id, qe.page_id) AS count_of_event_afer_page FROM qualified_events qe JOIN page_events pe ON qe.login_id = pe.login_id AND qe.page_id = pe.page_id ) -- 去重得到最终结果 SELECT DISTINCT login_id, login_type, login_name, count_of_event_before_page, count_of_event_afer_page, page_id FROM event_counts ORDER BY login_id, page_id;
思路说明
- page_events CTE:单独提取所有
login_type='page'的记录,获取每个login_id+page_id分区对应的页面时间戳。 - qualified_events CTE:筛选出需求指定的目标event记录(
login_name为null且login_type='event')。 - event_counts CTE:将目标event记录与对应分区的page记录关联,通过窗口函数
SUM()结合CASE逻辑,分别统计每个分区内page时间戳前后的目标event数量。 - 最终查询:用
DISTINCT去重,得到每个分区唯一的统计结果,与示例输出一致。
内容的提问来源于stack exchange,提问作者VarYaz
相关产品推荐
相关产品推荐

