首页 / 资讯中心 / 文章详情

连续登录问题的万能解法

连续登录问题的万能解法 ★ FEATURED ARTICLE
① 开篇这道题为什么值得会在窗口函数的面试题里“连续登录 N 天”几乎是绕不开的一类笔试会让你现场写面试会让你解释为什么。更关键的是它并不只考登录连续签到、连续交易、连续打卡甚至连续播放、连续下单都是同一道题换了业务外壳。把日期序列和序号序列对齐再用一个差值把它们压成组套路完全一致。所以今天要拿下的不是某一条 SQL而是一整类“连续”问题。② 原理虚拟起点先把问题说清楚SQL 怎么知道几条记录“连着”答案是给连续日期找一个共同标记。把每个用户的登录日期升序编号连续日期的日期值和序号会同步加一01-01 配 101-02 配 201-03 配 3。两者逐行相减加一和加一互相抵消差值恒定。这个差值就是“虚拟起点”它不一定是真实登录日却像指纹一样标记同一段连续登录。以 1001 为例user_idlogin_daternDATE_SUB(login_date, INTERVAL rn DAY)10012026-01-0112025-12-3110012026-01-0222025-12-3110012026-01-0332025-12-3110012026-01-0542026-01-01前三天都减出 2025-12-3101-05 因为中间断了一天序号只到 4减出来变成 2026-01-01。差值一变就说明进入了新的一段。这就是 DATE_SUB 能分组的根本原因也是面试官问“为什么能这样分组”时最想听到的解释。③ 模板完整代码完整模板只有三层先用 DISTINCT 去掉重复登录再在 t2 里算出序号 rn 和差值 grp最后按 user_id、grp 分组计数。上面的写法把编号和日期减编号放在同一个 CTE 里结构很紧凑分组后得到的cnt就是每一段连续登录的天数。WITH t1 AS ( SELECT DISTINCT user_id,login_date FROM t_login ), t2 AS( SELECT user_id,login_date,ROW_NUMBER() over(partition by user_id order by login_date) as rn, DATE_SUB(login_date,INTERVAL ROW_NUMBER() over(partition by user_id order by login_date) day) as grp FROM t1 ) select user_id,grp,count(*) as cnt FROM t2 GROUP BY user_id,grp测试数据跑出来的结果user_idgrpcnt10012025-12-31310012026-01-011④ 易错点三个坑第一个坑是不 DISTINCT。同一用户同一天登录两次ROW_NUMBER 会把同一天编成两个序号日期减序号的结果随之改变一段连续登录被硬生生拆开。若 login_date 是 DATETIME还要先用 DATE() 归一化到天。第二个坑是漏写 PARTITION BY user_id。多个用户的序号会首尾相接A 的最后一天和 B 的第一天可能被拼成一段差值相等只是巧合不是业务上的连续。第三个坑是把 grp 当成真实日期。它只是“假设这段从哪天开始、一天不落”算出的虚拟起点可能根本没人登录过作用仅是分组标识。面试时说“按虚拟起点分组”比说“按日期分组”准确得多。⑤ 总结面试口径可以记成一句“连续日期减连续序号差值被抵消成同一个值按这个值分组就是连续区间。”签到、交易、打卡、连续下单换掉表名和日期字段即可复用。下一篇如果有需要可以聊索引失效的六个常见场景。
阅读完成 · 觉得有帮助?
咨询建站