在 MySQL 中实现“连续天数计算”或者“连续登录天数统计”并不直接,但可以通过 日期差值技巧 + 分组统计的方法来完成。下面是详细教程,包括原理 + 示例 + SQL 写法:
🧠 原理讲解:连续日期的分组技巧
假设你有如下登录记录表:
CREATE TABLE user_login (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
login_date DATE
);
示例数据:
user_id | login_date |
---|---|
1 | 2025-08-01 |
1 | 2025-08-02 |
1 | 2025-08-03 |
1 | 2025-08-05 |
1 | 2025-08-06 |
1 | 2025-08-07 |
✅ 目标:找出用户每段连续登录的时间段和连续天数
📌 核心思想:
连续日期与“行号 – 日期差值”具有线性关系!
DATEDIFF(login_date, ROW_NUMBER) = 固定值
所以我们可以通过以下方式实现分组。
🧪 示例 SQL(MySQL 8+ 支持窗口函数)
WITH ranked_logins AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM user_login
),
grouped_logins AS (
SELECT
user_id,
login_date,
DATE_SUB(login_date, INTERVAL rn DAY) AS grp_key
FROM ranked_logins
)
SELECT
user_id,
MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS continuous_days
FROM grouped_logins
GROUP BY user_id, grp_key
ORDER BY user_id, start_date;
🧾 查询结果:
user_id | start_date | end_date | continuous_days |
---|---|---|---|
1 | 2025-08-01 | 2025-08-03 | 3 |
1 | 2025-08-05 | 2025-08-07 | 3 |
📌 找最长连续登录天数
在上面的 grouped_logins
基础上再包一层:
WITH ... -- 同上
SELECT
user_id,
MAX(continuous_days) AS max_continuous_days
FROM (
SELECT
user_id,
DATE_SUB(login_date, INTERVAL rn DAY) AS grp_key,
COUNT(*) AS continuous_days
FROM ranked_logins
GROUP BY user_id, grp_key
) AS t
GROUP BY user_id;
🧠 说明:
ROW_NUMBER()
:给每个用户登录记录按日期编号login_date - row_number
:连续日期的这个值是一样的(等差)DATE_SUB()
:生成“组键”来分组
❗ 如果你用的是 MySQL 5.x(不支持窗口函数)
需要使用变量实现 row_number()
:
SELECT
user_id, login_date,
@rn := IF(@prev_user = user_id, @rn + 1, 1) AS rn,
@prev_user := user_id
FROM
(SELECT * FROM user_login ORDER BY user_id, login_date) AS t,
(SELECT @rn := 0, @prev_user := NULL) AS vars;
后续逻辑类似,但代码较复杂,如需我可以为你继续整理。
✅ 总结
目标 | 方法 |
---|---|
连续登录时间段统计 | ROW_NUMBER + DATE_SUB 分组 |
最长连续登录天数 | 上面结果上再聚合 MAX() |
不支持窗口函数时的替代方案 | 使用变量模拟 row_number |
按用户分组统计连续登录 | PARTITION BY user_id 实现 |
好的,下面我来为你提供一个完整的 MySQL 解决方案,用于 统计每个用户的连续登录天数段落,并找出每个用户的 最长连续登录天数。
🧩 一、假设表结构如下:
CREATE TABLE user_login (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
login_date DATE NOT NULL
);
🧪 示例数据:
INSERT INTO user_login (user_id, login_date) VALUES
(1, '2025-08-01'),
(1, '2025-08-02'),
(1, '2025-08-03'),
(1, '2025-08-05'),
(1, '2025-08-06'),
(1, '2025-08-07'),
(2, '2025-08-01'),
(2, '2025-08-03'),
(2, '2025-08-04'),
(2, '2025-08-05');
✅ 二、统计连续登录的时间段(MySQL 8+ 版本)
WITH ranked AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM user_login
),
grouped AS (
SELECT
user_id,
login_date,
DATE_SUB(login_date, INTERVAL rn DAY) AS grp_key
FROM ranked
)
SELECT
user_id,
MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS continuous_days
FROM grouped
GROUP BY user_id, grp_key
ORDER BY user_id, start_date;
🥇 三、统计每个用户最长连续登录天数
WITH ranked AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM user_login
),
grouped AS (
SELECT
user_id,
DATE_SUB(login_date, INTERVAL rn DAY) AS grp_key
FROM ranked
)
SELECT
user_id,
MAX(continuous_days) AS max_continuous_days
FROM (
SELECT
user_id,
grp_key,
COUNT(*) AS continuous_days
FROM grouped
GROUP BY user_id, grp_key
) AS t
GROUP BY user_id;
✅ 四、查询结果(示意)
user_id | start_date | end_date | continuous_days |
---|---|---|---|
1 | 2025-08-01 | 2025-08-03 | 3 |
1 | 2025-08-05 | 2025-08-07 | 3 |
2 | 2025-08-01 | 2025-08-01 | 1 |
2 | 2025-08-03 | 2025-08-05 | 3 |
user_id | max_continuous_days |
---|---|
1 | 3 |
2 | 3 |
🛠 五、MySQL 5.x 兼容方案(无窗口函数)
如果你数据库版本低于 8.0,不支持 ROW_NUMBER()
,我可以提供带变量的方案(较复杂),可以继续给我说“我用的是 MySQL 5.7”等,我会按老版本适配。
发表回复