跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

怎样在MySQL中统计连续登录天数_利用窗口函数ROW_NUMBER差值法

ROW_NUMBER()差值法能识别连续登录,因同一用户连续日期的date-ROW_NUMBER()值恒定,形成分组标识;需用DATE(login_time)归一化并前置去重,MySQL 8.0+支持,5.7需变量或应用层处理。 为什么用
ROW_NUMBER()
差值法能识别连续登录? 核心在于:对同一用户的登录日期排序后,连续日期的
date - ROW_NUMBER()
值恒定。比如 2024-01-01、02、03 排序号为 1/2/3,则差值都是 2024-01-00(MySQL 会转成天数差),形成天然分组标识。 注意:必须用
DATE(login_time)
归一化时间,否则带时分秒的
DATETIME
会导致同一天多次登录被拆成多行。 常见错误现象:
GROUP BY user_id, DATE(login_time)
后再排序——这会丢失原始顺序,
ROW_NUMBER()
就乱了。 实际 SQL 写法与关键参数说明 假设表名
user_login
,字段为
user_id
、
login_time
(
DATETIME
类型):
SELECT user_id, MIN(login_date) AS start_date, MAX(login_date) AS end_date, COUNT(*) AS days FROM ( SELECT user_id, DATE(login_time) AS login_date, DATE(login_time) - INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY DATE(login_time) ) DAY AS grp FROM user_login ) t GROUP BY user_id, grp ORDER BY user_id, start_date;
要点说明:
PARTITION BY user_id
必须加,否则全表一起编号,用户间互相干扰
ORDER BY DATE(login_time)
要明确用日期排序,不是原始
login_time
INTERVAL ... DAY
是 MySQL 特有写法,其他数据库(如 PostgreSQL)需改用
login_date - ROW_NUMBER()::int
如果只要「当前连续多少天」,可在外层加
HAVING MAX(login_date) = CURDATE()
遇到重复登录或数据不干净怎么办? 真实场景中,用户一天可能登录多次,直接
GROUP BY user_id, DATE(login_time)
去重最稳妥——但必须在窗口函数之前做,否则
ROW_NUMBER()
仍会为同一天多条记录分配不同序号。 修正写法(子查询先去重): MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载
SELECT user_id, MIN(login_date) AS start_date, MAX(login_date) AS end_date, COUNT(*) AS days FROM ( SELECT user_id, login_date, login_date - INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY login_date ) DAY AS grp FROM ( SELECT DISTINCT user_id, DATE(login_time) AS login_date FROM user_login ) t0 ) t GROUP BY user_id, grp;
性能提示:如果表很大,
DISTINCT
+ 窗口函数组合可能慢,建议在
(user_id, DATE(login_time))
上建联合索引,或预计算每日登录标记表。 这个方法在 MySQL 5.7 和 8.0 的兼容性差异
ROW_NUMBER()
是 MySQL 8.0+ 才支持的窗口函数,MySQL 5.7 及更早版本会报错
FUNCTION xxx.ROW_NUMBER does not exist
。 5.7 替代方案只能用变量模拟,但风险高: 变量执行顺序不保证,尤其在
ORDER BY
和
JOIN
混用时极易出错 无法在子查询中安全复用变量值 官方已明确不推荐用于生产环境 如果必须支持 5.7,建议改用应用层聚合(如 Python/Java 拉取排序后日期列表再扫描),比硬套变量更可靠。 真正容易被忽略的是:差值法依赖日期严格连续,中间缺一天就断开;如果业务需要“7天内最多断1天也算连续”,就得换用自连接或递归 CTE,不再是简单差值能解决的了。

相关文章