38人参与 • 2025-09-26 • MsSqlserver
前几天刷手机时看到一道有趣的 sql 题:查询连续 3 天登录的用户。这让我联想到之前讨论过的开窗函数,深入思考后发现其实还有多种实现方式。今天就来和大家分享几种解决方案,欢迎一起讨论!
1.创建用户登录记录表t_login_records,包含用户 id 和登录日期两个核心字段
drop table if exists t_login_records;#若表存在删除
-- 创建用户登录记录表
create table t_login_records (
id int primary key auto_increment,
user_id int not null,
login_date date not null
)engine=innodb default charset=utf8 collate=utf8_unicode_ci comment='用户登录记录表';2.插入测试数据
-- 查看表结构 desc t_login_records;

insert into t_login_records (user_id, login_date) values (1, '2023-01-01'), (1, '2023-01-02'), (1, '2023-01-03'), -- 用户1连续3天登录 (1, '2023-01-05'), (2, '2023-01-01'), (2, '2023-01-02'), (2, '2023-01-04'), -- 用户2不连续 (3, '2023-01-01'), (3, '2023-01-02'), (3, '2023-01-03'), -- 用户3连续3天登录 (3, '2023-01-04'), -- 用户3连续4天登录 (4, '2023-01-01'), (4, '2023-01-03'), (4, '2023-01-05'), -- 用户4不连续 (5, '2023-01-01'), (5, '2023-01-02'), (5, '2023-01-03'), -- 用户5连续3天登录 (5, '2023-01-04'), -- 用户5连续4天登录 (5, '2023-01-05'), -- 用户5连续5天登录 (5, '2023-02-01'), -- 断开 (5, '2023-02-02'), -- 用户5再连续2天登录 (5, '2023-02-03'); -- 用户5再连续3天登录 select * from t_login_records;

-- 方法1:自连接查询 select distinct t1.user_id from t_login_records t1 join t_login_records t2 on t1.user_id = t2.user_id and datediff(t2.login_date, t1.login_date) = 1 join t_login_records t3 on t1.user_id = t3.user_id and datediff(t3.login_date, t1.login_date) = 2;
user_id为1、3、5的用户
t2.login_date=t1.login_date+1t3.login_date=t1.login_date+2distinct过滤重复的user_iduser_id=1的用户在 2023-01-01、2023-01-02、2023-01-03 连续登录:t1(2023-01-01) → t2(2023-01-02) → t3(2023-01-03),匹配成功。user_id=2的用户仅在 2023-01-01 和 2023-01-02连续登录:
lead()获取每个用户后续的登录日期,直接判断是否连续。-- 方法2:窗口函数(适用于支持lead函数的数据库,如mysql 8.0+、postgresql)
select distinct user_id
from (
select
user_id,
login_date,
lead(login_date, 1) over (partition by user_id order by login_date) as next_day,
lead(login_date, 2) over (partition by user_id order by login_date) as next_2_days
from t_login_records
) t
where datediff(next_day, login_date) = 1
and datediff(next_2_days, login_date) = 2;user_id依然为1、3、5的用户
lead(login_date, 1):获取当前记录的下一条日期。lead(login_date, 2):获取当前记录的下两条日期。next_day = login_date + 1且next_2_days = login_date + 2。不满足条件,用户4未被选中。

-- 方法3:日期差值分组(适用于支持row_number的数据库)
select user_id
from (
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 t_login_records
) t
group by user_id, grp
having count(distinct login_date) >= 3;user_id依然为1、3、5的用户
计算分组标识grp和分组统计
row_number()为每个用户的登录记录分配连续序号(1,2,3…)。date_sub(login_date,row_number()):将日期减去序号,连续日期会得到相同的结果。user_id和grp分组,统计每组的日期数量,若≥3则为连续登录。
date_sub(date, interval expr unit)是 sql 中的一个日期函数,用于从指定日期中减去一个时间间隔。
interval expr unit:指定要减去的时间间隔interval:固定关键字,表示时间间隔expr 是一个数值unit 是时间单位(如 day、month、year 等)| 方法 | 优点 | 缺点 |
|---|---|---|
| 自连接 | 简单直接,兼容性强 | 性能差(多次扫描表) |
| 窗口函数 | 逻辑清晰,一步到位 | 需数据库支持窗口函数 |
| 日期差值 | 性能最优,逻辑巧妙 | 理解难度较高 |
这道题虽然仅要求查询连续 3 天登录的用户,但通过这三种方法我们可以举一反三。如果要查询连续 4 天、5 天甚至 n 天登录的用户,第三种日期差值分组法更具优势,只需修改 having count(distinct login_date) >= n 即可实现 “一力破万法” 的效果!
到此这篇关于sql语句查询连续n天登录用户的文章就介绍到这了,更多相关sql连续n天登录用户内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论