识别用户连续登录行为是用户留存分析、活跃度统计场景下的常见需求,核心逻辑是通过用户的登录日期记录,判断相邻登录日期是否连续,进而统计连续登录的天数。下面介绍两种常用的SQL实现方案。

基础数据准备
首先假设我们有用户登录记录表user_login_log,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| user_id | int | 用户ID |
| login_date | date | 登录日期 |
表中存在部分示例数据:
-- 示例数据插入语句 INSERT INTO user_login_log (user_id, login_date) VALUES (1, '2024-01-01'), (1, '2024-01-02'), (1, '2024-01-03'), (1, '2024-01-05'), (2, '2024-01-01'), (2, '2024-01-03'), (2, '2024-01-04');
方案一:ROW_NUMBER窗口函数法
该方案的核心思路是,先对每个用户的登录日期按升序排序生成行号,再用登录日期减去行号对应的天数,如果连续登录,这个差值会保持一致。
实现步骤
- 第一步:对每个用户的登录日期去重,避免同一天多次登录影响统计结果
- 第二步:用
ROW_NUMBER()窗口函数按用户分组、登录日期升序生成排序号 - 第三步:计算登录日期减去排序号天数的差值,作为连续分组的标识
- 第四步:按用户和差值分组,统计每个组的天数,即为连续登录天数
完整SQL代码
WITH distinct_login AS (
-- 去重同一用户同一天的登录记录
SELECT DISTINCT user_id, login_date
FROM user_login_log
),
login_with_rn AS (
SELECT
user_id,
login_date,
-- 按用户分组,登录日期升序生成行号
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM distinct_login
),
login_group AS (
SELECT
user_id,
login_date,
-- 登录日期减去行号天数,连续登录的差值相同
DATE_SUB(login_date, INTERVAL rn DAY) AS group_flag
FROM login_with_rn
)
-- 统计每个用户的连续登录天数
SELECT
user_id,
MIN(login_date) AS start_login_date,
MAX(login_date) AS end_login_date,
COUNT(*) AS continuous_days
FROM login_group
GROUP BY user_id, group_flag
ORDER BY user_id, start_login_date;
上述代码执行后,会得到每个用户每段连续登录的起始日期、结束日期和连续天数,比如用户1会有两段连续登录记录,分别是1月1日到1月3日共3天,1月5日共1天。
方案二:差值法(LAG窗口函数版)
该方案不需要生成行号,而是通过LAG窗口函数获取用户上一次的登录日期,判断两次登录日期的差值是否为1天,来标记连续登录的起始点。
实现步骤
- 第一步:同样先对用户的登录日期去重
- 第二步:用
LAG函数获取每个用户上一次的登录日期,计算当前登录日期和上一次登录日期的差值 - 第三步:如果差值为1天,说明是连续登录,否则是当前连续段的起始点,给起始点标记分组ID
- 第四步:按分组ID统计连续登录天数
完整SQL代码
WITH distinct_login AS (
SELECT DISTINCT user_id, login_date
FROM user_login_log
),
login_with_prev AS (
SELECT
user_id,
login_date,
-- 获取上一次登录日期
LAG(login_date) OVER (PARTITION BY user_id ORDER BY login_date) AS prev_login_date
FROM distinct_login
),
login_mark AS (
SELECT
user_id,
login_date,
-- 如果和上一次登录差1天,不属于新段,否则属于新段,用累计和生成分组ID
SUM(CASE WHEN DATEDIFF(login_date, prev_login_date) = 1 THEN 0 ELSE 1 END)
OVER (PARTITION BY user_id ORDER BY login_date) AS group_id
FROM login_with_prev
)
-- 统计连续登录天数
SELECT
user_id,
MIN(login_date) AS start_login_date,
MAX(login_date) AS end_login_date,
COUNT(*) AS continuous_days
FROM login_mark
GROUP BY user_id, group_id
ORDER BY user_id, start_login_date;
两种方案对比
| 对比维度 | ROW_NUMBER法 | 差值法(LAG版) |
|---|---|---|
| 逻辑复杂度 | 较低,依赖日期减行号的特性 | 稍高,需要判断日期差值 |
| 适用场景 | 所有支持窗口函数的数据库 | 支持LAG函数的数据库 |
| 性能表现 | 排序和差值计算开销较小 | 需要额外计算日期差值,开销略高 |
实际使用中可以根据数据库支持的函数类型和业务需求选择合适的方案,两种方案都能准确识别用户的连续登录行为。
SQL窗口函数ROW_NUMBER连续登录差值法修改时间:2026-07-06 22:21:25