SQL语句查询连续N天登录用户(解决方案)

 更新时间:2025年09月26日 10:02:49   作者:白话说数  
本文给大家介绍SQL语句查询连续N天登录用户,本文通过场景分析结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

前几天刷手机时看到一道有趣的 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.自连接查询

  • 原理: 通过三次连接同一张表,强制匹配同一用户的三条登录记录,且日期依此相差 1 天
-- 方法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的用户

  • 执行步骤: 自连接将表t1(基准记录)与t2(次日记录)、t3(第三日记录)连接,确保
  • 用户相同
    • t2.login_date=t1.login_date+1
    • t3.login_date=t1.login_date+2
    • DISTINCT过滤重复的user_id
  • 示例数据验证:
    • user_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连续登录:
    • 无法找到连续三天的记录,匹配失败。

2.窗口函数

  • 原理: 使用窗口函数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 + 1next_2_days = login_date + 2
  • 示例数据验证:
    • 用户1的第一条记录(2023-01-01):
    • next_day=2023-01-02(差值1天)
    • next_2_days=2023-01-03(差值2天)
    • 满足条件,用户1被选中。
    • 用户4的第一条记录(2023-01-01):
    • next_day=2023-01-03
    • next_2_days=2023-01-05

不满足条件,用户4未被选中。

3.日期差值分组

  • 原理: 将每个登录日期减去其在用户组内的排序序号,连续日期会得到相同的差值,通过分组统计差值出现次数即可。
-- 方法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_idgrp分组,统计每组的日期数量,若≥3则为连续登录。

  • DATE_SUB()函数: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天登录用户内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论