连续登录统计是SQL面试和业务分析中的高频需求,核心目标是计算用户连续登录的最大天数、连续登录的起始结束日期等信息,下面拆解具体实现步骤。

第一步:准备基础登录数据
首先需要确认原始登录表的结构,通常至少包含用户ID和登录日期两个核心字段,假设原始表名为user_login_log,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| user_id | int | 用户唯一标识 |
| login_date | date | 用户登录日期,无重复,即同一用户同一天只算一次登录 |
如果原始表中存在同一用户同一天多条登录记录,需要先做去重处理,示例代码如下:
-- 去重得到每个用户每天的登录记录 SELECT DISTINCT user_id, login_date FROM user_login_log
第二步:为每个用户的登录日期排序并生成行号
按照用户分组,对登录日期升序排序,给每个用户的登录记录生成连续递增的行号,这是后续计算的核心基础。使用窗口函数ROW_NUMBER()实现:
SELECT
user_id,
login_date,
-- 按用户分组,登录日期升序排序生成行号
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM (
-- 先去重得到用户每日登录记录
SELECT DISTINCT user_id, login_date
FROM user_login_log
) t1
第三步:计算日期与行号的差值
连续登录的日期是依次递增1天的,而行号是依次递增1的,因此连续登录的日期减去对应的行号,得到的结果会是同一个固定值。我们用登录日期减去行号对应的天数,得到差值日期:
SELECT
user_id,
login_date,
rn,
-- 登录日期减去行号天,得到差值日期
DATE_SUB(login_date, INTERVAL rn DAY) AS diff_date
FROM (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM (
SELECT DISTINCT user_id, login_date
FROM user_login_log
) t1
) t2
这里如果是PostgreSQL数据库,日期减法语法为login_date - rn * INTERVAL '1 day',如果是SQL Server则是DATEADD(day, -rn, login_date),根据实际数据库调整即可。
第四步:按用户和差值日期分组统计连续登录天数
同一个用户下,diff_date相同的所有记录,就是该用户的一段连续登录记录,我们按user_id和diff_date分组,统计每组的数量就是这段连续登录的天数,同时可以拿到这段连续登录的起始和结束日期:
SELECT
user_id,
diff_date,
-- 连续登录天数
COUNT(*) AS continuous_days,
-- 连续登录起始日期
MIN(login_date) AS start_date,
-- 连续登录结束日期
MAX(login_date) AS end_date
FROM (
SELECT
user_id,
login_date,
rn,
DATE_SUB(login_date, INTERVAL rn DAY) AS diff_date
FROM (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM (
SELECT DISTINCT user_id, login_date
FROM user_login_log
) t1
) t2
) t3
GROUP BY user_id, diff_date
第五步:根据需求提取最终结果
如果需要统计每个用户的最大连续登录天数,只需要在上一步结果的基础上按用户分组取最大值即可:
SELECT
user_id,
MAX(continuous_days) AS max_continuous_login_days
FROM (
SELECT
user_id,
diff_date,
COUNT(*) AS continuous_days,
MIN(login_date) AS start_date,
MAX(login_date) AS end_date
FROM (
SELECT
user_id,
login_date,
rn,
DATE_SUB(login_date, INTERVAL rn DAY) AS diff_date
FROM (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM (
SELECT DISTINCT user_id, login_date
FROM user_login_log
) t1
) t2
) t3
GROUP BY user_id, diff_date
) t4
GROUP BY user_id
如果需要查询连续登录天数大于等于7天的用户记录,只需要在第四步的结果上增加HAVING continuous_days >= 7条件即可。
核心思路总结
连续登录问题的本质是找到日期序列中的连续片段,通过行号和日期的差值将连续的日期映射到同一个分组,再对分组做聚合统计,就能得到所有连续登录的片段信息,后续根据业务需求提取对应结果即可。这种方法适用于所有需要统计连续时间序列的场景,比如连续签到、连续消费等。