SQL查询需求:筛选按顺序执行动作1、2、3且间隔小于1小时的用户会话
解决用户按顺序执行1→2→3且间隔小于1小时的SQL查询方案
别发愁啦!这个需求其实就是要追踪用户动作的顺序和时间间隔,咱们一步步来搞定它。首先我得先假设你的数据表结构(如果和实际有出入,你可以对应调整字段名):假设表名为user_actions,包含字段user_id(用户ID)、action_id(动作编号,比如1、2、3)、action_time(动作执行的时间戳)。
方法一:支持中间有其他动作的通用方案
如果你的需求是「用户执行了1,之后执行了2(间隔<1小时),之后又执行了3(和2间隔<1小时)」,不管中间有没有其他动作,那用自连接+窗口函数的方案最稳妥:
WITH ranked_actions AS ( SELECT user_id, action_id, action_time, -- 给每个用户的动作按时间排序,生成序号 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY action_time) AS action_rank FROM user_actions ) -- 关联三次动作记录,匹配1→2→3的顺序和时间要求 SELECT DISTINCT r1.user_id FROM ranked_actions r1 JOIN ranked_actions r2 ON r1.user_id = r2.user_id AND r2.action_rank > r1.action_rank -- 确保动作2在动作1之后 AND r2.action_id = 2 -- 动作2和动作1的间隔小于1小时(MySQL写法,其他数据库可调整) AND TIMESTAMPDIFF(HOUR, r1.action_time, r2.action_time) < 1 JOIN ranked_actions r3 ON r2.user_id = r3.user_id AND r3.action_rank > r2.action_rank -- 确保动作3在动作2之后 AND r3.action_id = 3 -- 动作3和动作2的间隔小于1小时 AND TIMESTAMPDIFF(HOUR, r2.action_time, r3.action_time) < 1 WHERE r1.action_id = 1;
代码解释:
ranked_actions这个CTE(公共表表达式)给每个用户的动作按时间排了序号,保证我们能严格按顺序关联动作。- 三次自连接分别匹配动作1、2、3,通过
action_rank确保顺序,通过TIMESTAMPDIFF检查时间间隔。 DISTINCT用来避免同一个用户因为有多个符合条件的动作序列被重复返回。
方法二:仅适用于1→2→3连续执行的高效方案
如果你的需求是用户必须连续执行1、2、3(中间没有其他动作),那用LEAD窗口函数会更简洁高效:
WITH action_sequence AS ( SELECT user_id, action_id, action_time, -- 获取当前动作的下一个动作ID和时间 LEAD(action_id, 1) OVER (PARTITION BY user_id ORDER BY action_time) AS next_action, LEAD(action_time, 1) OVER (PARTITION BY user_id ORDER BY action_time) AS next_action_time, -- 获取当前动作的下下个动作ID和时间 LEAD(action_id, 2) OVER (PARTITION BY user_id ORDER BY action_time) AS second_next_action, LEAD(action_time, 2) OVER (PARTITION BY user_id ORDER BY action_time) AS second_next_action_time FROM user_actions ) SELECT DISTINCT user_id FROM action_sequence WHERE action_id = 1 AND next_action = 2 AND second_next_action = 3 AND TIMESTAMPDIFF(HOUR, action_time, next_action_time) < 1 AND TIMESTAMPDIFF(HOUR, next_action_time, second_next_action_time) < 1;
代码解释:
LEAD函数可以直接获取当前行之后第N行的数据,这里我们一次性拿到当前动作的下一个和下下个动作信息。- 直接筛选出当前动作是1,下一个是2,下下个是3,且相邻间隔都小于1小时的用户。
注意事项
- 不同数据库的时间差函数写法不同:比如PostgreSQL用
EXTRACT(HOUR FROM r2.action_time - r1.action_time) < 1,SQL Server用DATEDIFF(HOUR, ...),你要根据自己用的数据库调整。 - 确保
action_time是时间类型(比如TIMESTAMP、DATETIME),否则无法正确计算时间差。 - 如果需要返回具体的会话详情(比如会话的开始/结束时间),可以修改
SELECT语句,比如加上r1.action_time AS session_start, r3.action_time AS session_end。
内容的提问来源于stack exchange,提问作者Alex Nikitin
相关产品推荐
相关产品推荐

