订阅更新

SQL 如何计算用户连续登录天数?

面试问 114 约 2 分钟读完

本文目录
  1. 面试怎么回答
  2. 第一步先去重
  3. 第二步构造连续岛
  4. 第三步聚合区间
  5. 边界决定业务答案
  6. 为什么不能只回答概念?
  7. 落地时我会检查什么?
  8. 一个典型场景

面试怎么回答

我会先按用户和业务自然日去重,再按日期排序生成 ROW_NUMBER。用登录日期减去行号对应天数得到稳定分组键,连续日期会落在同一组;随后按用户和分组键统计区间长度,取最大值。最后我会补充时区、补签、同日多次登录和并列区间的口径,否则 SQL 正确也可能业务错误。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

业务只给了两列:user_id 和 login_date,要求算出每个用户最长连续登录天数。

很多人会先想到 LAG,但真正决定答案是否正确的,是去重、连续分组和边界日期。

连续登录属于典型的 Gap and Island 问题:先把日期去重,再构造稳定分组键,最后按组聚合。

第一步先去重

同一用户一天可能登录多次。若直接排序,重复日期会让行号递增却不让日期变化,破坏后续分组。第一层应先按用户和自然日去重,并统一时区口径。

第二步构造连续岛

对去重后的日期按用户排序生成 ROW_NUMBER,再用登录日期减去行号对应的天数。连续日期减去连续行号会得到同一个锚点,这个锚点就是连续区间的分组键。

连续区间算法

第三步聚合区间

按用户和分组键统计天数,就能得到每段连续区间的开始日、结束日和长度。再用 ROW_NUMBER 或 MAX 取最长区间,并明确并列时取最近还是全部保留。

边界决定业务答案

“连续”按自然日还是滚动 24 小时?补签是否算登录?跨时区用户按本地日还是 UTC?SQL 写法可以相同,但日期归属规则不同,结果会完全不同。

为什么不能只回答概念?

“误区:相邻日期做一次 LAG 就结束”之所以常见,是因为它在理想数据和单次执行里往往说得通。但生产环境会加入数据规模、异常值、并发、版本、失败重试和下游口径,这些条件一变化,只记住术语就很容易给出错误结论。

所以我会把 第一步先去重、第二步构造连续岛、第三步聚合区间、边界决定业务答案 串成一条完整链路。最终判断标准不是某个函数或配置是否出现,而是能否稳定得到可解释、可验证、可恢复的业务结果。

落地时我会检查什么?

  • 输入边界:确认数据范围、时间口径、主键和异常值是否符合假设。
  • 执行过程:观察分区、并行度、状态、Shuffle 或资源变化,验证方案是否真正生效。
  • 输出结果:用行数、唯一性、关键指标和样本明细证明结果正确,而不是只看任务成功。
  • 失败恢复:说明重跑、回滚、版本兼容和责任人,避免一次成功后无人维护。

这些检查不一定全部写进一条 SQL 或一个任务,但面试时能主动补充,说明你回答的不是背诵题,而是在描述一套可上线的工程方案。

一个典型场景

一个典型场景是海外业务统一按 UTC 截断日期。用户本地时间晚上 23 点和第二天凌晨 1 点连续活跃,在 UTC 中可能落在同一天,最长连续天数被低估。团队一开始反复调整窗口函数,最后发现根因不是 SQL,而是自然日口径没有绑定用户时区。

先定义“天”和“连续”,再写连续区间 SQL。

刷题进度保存在当前浏览器