最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
怎样通过SQL分组查询找出连续登录天数超过3天的用户
时间:2026-07-03 10:57:46 编辑:袖梨 来源:一聚教程网
核心思路是用ROW_NUMBER()编号后日期减编号得相同锚点日期以标识连续段;需按user_id分组排序、统一日期类型、建联合索引优化性能,并注意去重和数据库语法差异。
用 ROW_NUMBER() 和日期差构造连续登录组
核心思路是:把每个用户的登录日期按顺序编号,再用日期减去编号,同一连续段的结果会相同。比如 2024-01-01、02、03 编号为 1/2/3,相减都得 2023-12-31 —— 这个“锚点日期”就是连续段的起始基准。
实操时注意三点:
-
ROW_NUMBER()必须按user_id分组、login_date排序,否则编号错乱 - 日期类型要统一,
login_date不能是DATETIME或带时分秒,否则需先CAST(login_date AS DATE) - MySQL 8.0+、PostgreSQL、SQL Server 都支持
ROW_NUMBER();MySQL 5.7 及更早版本需用变量模拟,容易出错,建议升级或换方案
GROUP BY 锚点日期后筛选长度
构造出锚点列(比如叫 grp)后,对 user_id 和 grp 联合分组,再用 COUNT(*) 算连续天数。
典型写法:
SELECT user_idFROM ( SELECT user_id, login_date, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS grp FROM login_log) tGROUP BY user_id, grpHAVING COUNT(*) > 3;
注意:HAVING COUNT(*) > 3 表示“超过3天”,即至少4天连续;若要“≥3天”,改用 >= 3。
处理重复登录和跨年边界
用户同一天多次登录会导致 COUNT(*) 偏大,必须先去重:
- 在子查询里加
DISTINCT user_id, login_date,或用GROUP BY user_id, login_date预聚合 - 跨年不构成障碍,
DATE_SUB在 MySQL 中能正确处理如2023-12-31 - INTERVAL 1 DAY = 2023-12-30,无需额外适配 - 但若数据库用的是 Oracle 或 PostgreSQL,
DATE运算语法不同:PostgreSQL 用login_date - ROW_NUMBER() OVER (...)::INT,Oracle 用login_date - ROW_NUMBER() OVER (...)
性能关键:索引必须覆盖 user_id + login_date
没索引时,PARTITION BY user_id ORDER BY login_date 会触发全表扫描,百万级数据可能卡住。
建索引命令:
CREATE INDEX idx_user_login ON login_log (user_id, login_date);
这个联合索引同时支撑分组、排序和去重,比单列索引有效得多。如果表已有主键含这两列,确认顺序是否匹配——user_id 必须在前。
连续登录分析本身不难,难点在数据质量:空值、时区混杂、日志漏采都会让 grp 计算失准,上线前务必用真实样本跑一遍中间结果。
相关文章
- 刀剑缭乱2026公测兑换码大全一览 07-05
- 崩坏星穹铁道4.0卡池7个新角色一览 07-05
- 明日方舟终末地开服工业蓝图一览 工业蓝图作用与使用思路解析 07-05
- 原神梦之树怎么开启 梦之树开启条件 07-05
- 帕瓦勇者传说持续伤害阵容搭配推荐 07-05
- 明日方舟:终末地全新玩法 蚀像寻遗怎么玩介绍 07-05