2025面试题目:mysql查询连续登录天数
题目内容:
一个数据表中,有两个字段:登录用户名,登录日期时间。现在要查询一个用户连续登录天数是多少,应该怎么查询?
被问到的当时,感觉应该是挺简单的需求,但是没有做过类似的开发,一时间想不到怎么做sql查询。后面研究了一下,发现挺简单的。
假设表结构如下
字段名 | 类型 |
---|---|
username |
VARCHAR |
login_time |
DATETIME |
目标如下:
给定一个用户名,查询该用户最长一次连续登录的天数(如最近连续登录了3天,或今天没有登录则中断)。
思路说明:
-
先对每个登录日期去重并排序;
-
使用
ROW_NUMBER()
给每行编号; -
把“日期”和“行号”做差,得到同一个“连续段”的标识;
-
根据这个差值分组后
GROUP BY
即可得到每段连续天数; -
最后只取“最近的一段”,看它有几天。
示例 SQL:
WITH user_logins AS ( SELECT DISTINCT DATE(login_time) AS login_date FROM login_table WHERE username = 'alice' ), numbered AS ( SELECT login_date, ROW_NUMBER() OVER (ORDER BY login_date) AS rn FROM user_logins ), grouped AS ( SELECT login_date, DATE_SUB(login_date, INTERVAL rn DAY) AS grp_key FROM numbered ) SELECT COUNT(*) AS consecutive_days, MAX(login_date) AS last_day FROM grouped GROUP BY grp_key ORDER BY last_day DESC LIMIT 1;
核心逻辑就是:
登录日期 - 序号 = 分组标识
只要这个值一致,说明这些天是连续的。中断时,这个值就会变,从而实现分段。
举个例子
我们有如下用户登录记录(按日期去重并升序):
login_date | row_number |
---|---|
2024-06-25 | 1 |
2024-06-26 | 2 |
2024-06-27 | 3 |
2024-06-29 | 4 |
2024-06-30 | 5 |
row_number
是用ROW_NUMBER() OVER (ORDER BY login_date)
生成的连续序号。
然后进行做差(login_date - row_number
)
我们想找“连续登录的天数”,你可以这样理解:
-
正常情况下,如果用户每天连续登录:
-
登录日期 +1,行号也 +1 → 二者的差值不变
-
-
但如果中断了某天没登录,差值就会发生跳变!
所以我们构造一个字段:
DATE_SUB(login_date, INTERVAL row_number DAY) AS grp_key
这个表达式的意思是:“用日期减去行号的天数”,我们看看结果👇:
login_date | row_number | grp_key |
---|---|---|
2024-06-25 | 1 | 2024-06-24 |
2024-06-26 | 2 | 2024-06-24 |
2024-06-27 | 3 | 2024-06-24 |
2024-06-29 | 4 | 2024-06-25 |
2024-06-30 | 5 | 2024-06-25 |
你会发现:
-
前三行的差值是一样的(2024-06-24)👉属于同一组
-
后两行的差值是一样的(2024-06-25)👉属于另一组
现在每组都有相同的 grp_key
,代表一段连续登录的记录了!
最后分组取取最大数量就好了。