自连接查询连续三天登录用户是将同一张登录表用三个别名(如t1、t2、t3)自连接,通过DATEDIFF(t2.login_date, t1.login_date)=1且DATEDIFF(t3.login_date, t2.login_date)=1严格验证相邻两天的连续性,确保第1天→第2天→第3天完整链路,再用SELECT DISTINCT t1.user_id去重输出满足条件的用户。

什么是自连接查询连续三天登录的用户
自连接不是特殊语法,就是 JOIN 同一张表两次或多次,用不同别名区分。判断“连续三天登录”,核心是把同个用户的任意两条记录(比如 t1 和 t2)按日期差为 1 天关联,再引入第三条(t3)补上第二天到第三天的差值。注意:必须确保日期字段是 DATE 类型(不含时间),否则 DATEDIFF 或 t2.login_date = DATE_ADD(t1.login_date, INTERVAL 1 DAY) 可能因时分秒不等而失败。
MySQL 中用 DATEDIFF 实现三日连续登录
MySQL 常用 DATEDIFF 计算整数天数差,写法直观。但要注意它只认日期部分,自动忽略时间——这对登录日志反而是优势。
关键点:
-
DATEDIFF(t2.login_date, t1.login_date) = 1表示 t2 是 t1 的后一天 -
DATEDIFF(t3.login_date, t2.login_date) = 1表示 t3 是 t2 的后一天 - 三个别名必须来自同一张表,且都加
WHERE过滤有效登录(如非 NULL、非测试账号) - 用
DISTINCT t1.user_id避免同一用户多组连续三日被重复计数
SELECT DISTINCT t1.user_id FROM login_log t1 JOIN login_log t2 ON t2.user_id = t1.user_id AND DATEDIFF(t2.login_date, t1.login_date) = 1 JOIN login_log t3 ON t3.user_id = t1.user_id AND DATEDIFF(t3.login_date, t2.login_date) = 1 WHERE t1.login_date IS NOT NULL AND t2.login_date IS NOT NULL AND t3.login_date IS NOT NULL;
PostgreSQL / SQL Server 要用 DATE arithmetic 而非 DATEDIFF
PostgreSQL 没有 DATEDIFF,得用 t2.login_date = t1.login_date + INTERVAL '1 day';SQL Server 则用 DATEADD(day, 1, t1.login_date)。写错会导致全表扫描或空结果。
常见坑:
- PostgreSQL 中
login_date + '1 day'是简写,但严格推荐写成login_date + INTERVAL '1 day',避免隐式类型转换歧义 - SQL Server 若字段是
datetime2,DATEADD没问题;但若混用smalldatetime,精度丢失可能导致“看似同一天实则差一秒”,建议统一转DATE再比 - 所有数据库中,若表无复合索引
(user_id, login_date),这个自连接会极慢——尤其百万级日志表
为什么不能只连两次然后用 BETWEEN?
有人试过:JOIN 一次,再用 WHERE t2.login_date BETWEEN t1.login_date AND t1.login_date + 2 ——这只能保证“存在某次登录在三天窗口内”,不保证**连续**。比如用户在第1、2、4天登录,也满足条件,但缺了第3天。
真正连续的逻辑必须显式验证:第1天 → 第2天 → 第3天,三段相邻关系缺一不可。少一个 JOIN,就漏掉“顺序性”约束。
另外,如果业务要求“任意连续三天”(比如 5.1–5.3、5.2–5.4 都算),上面三表自连接天然覆盖——因为每组三元组独立成立,无需额外去重逻辑。










