SQL: 求连续登录天数,间隔1天也算作连续

问题

需求 : 计算每个用户最大的连续登录天数,可以间隔一天。解释:如果一个用户在第 1, 3, 5, 6, 9 天登录游戏,则视为连续 6 天登录

CREATE TABLE log (
  id VARCHAR(1),
  time date
);

insert into log values('A','2024-12-20');
insert into log values('A','2024-12-24');
insert into log values('A','2024-12-22');
insert into log values('A','2024-12-25');
insert into log values('A','2024-12-28');
insert into log values('A','2024-12-30');
insert into log values('A','2024-12-31');
insert into log values('B','2024-12-20');
insert into log values('B','2024-12-21');
insert into log values('B','2024-12-23');
insert into log values('B','2024-12-24');

如上表格,正确结果应该输出一下结果。

解释:

  1. A用户有两段连续登录记录,一段是从2024-12-20登录到2024-12-25 ,中间间隔日期只有1天,所以共6天,另一段是2024-12-282024-12-31,中间间隔日期只有15天,共4天。这里请注意区分为什么是两段连续登录而不是一段连续登录,原因:A用户2024-12-282024-12-30是间隔2天。
  2. B用户有一段连续登录记录,是从2024-12-20登录到2024-12-24 ,共5天
  3. A用户取最大连续登录为6天, B用户取最大连续登录是5天
id cont_day
A 6
B 5
方案:

两个方法的核心切入点都是

  1. 求每条记录与前一条记录的差值,只是后续处理差值的逻辑不同。
  2. 目的都是找出一个字段,能够区分不同的连续登录片段。
方法一:

思路:

  1. 计算每个记录的日期(time字段)与前一条记录的日期的差值, 记为diff字段, 注意按日期排序,方法是使用lag开窗函数
  2. 如果差值(diff字段)小于等于2,说明间隔小于等于1天,直接保留差值的原本值即可,如果差值大于2天,说明间隔大于1天,已经开始新的连续登录日期了, 我们把差值置为0。
  3. 对差值累加求和sum(注意要加上order by, 若无order by则无法实现累加功能), sum实际上表达的是“ 与 连续登录区域的第一天的差值” ,这个可以想一想。我们将求和sum记为con_day字段
  4. 使用日期 减去 con_day,即可求出每段连续登录记录的第一天, 记为start_date
  5. group by id, start_date, 然后求出每个group的最大和最小日期,使用“最大日期 - 最小日期+1” ,就是连续登录连段的连续登录天数,记为cont_day
  6. 再group by id, 求最大的cont_day, 就是答案。
select id, max(cont_day) as max_cont_day
from
(
  select id, start_date, max(time) as maxd , min(time) as mind, datediff(max(time), min(time)) + 1 as cont_day
  from
  (
    select id, time, pre_date, diff, con_day, date_sub(time, interval con_day day) as start_date
    from
    (
      select id, time, pre_date, diff, sum(diff) over(partition by id order by time) as con_day
      from
      (
        select id, time ,pre_date, if(datediff(time, pre_date) > 2, 0, datediff(time, pre_date))  as diff
        from
        (
          SELECT 
            id, time,
            lag(time,1,'1970-01-01') over(partition by id order by time) as pre_date
          from log
        ) t0
      ) t1
    ) t2
  ) t3
  group by id, start_date
) t4
group by id
方法二

思路:

  1. 计算每个记录的日期(time字段)与前一条记录的日期的差值, 记为diff字段, 注意按日期排序,方法是使用lag开窗函数
  2. 如果差值(diff字段)小于等于2,说明间隔小于等于1天,则置为0,如果差值大于2天,说明间隔大于1天,已经开始新的连续登录日期了, 我们把差值置为1。 diff实际表达了是否开始了一个新的连续片段。
  3. 对差值累加求和sum(注意要加上order by, 若无order by则无法实现累加功能), 我们将求和sum记为flag字段。每开始一段新的连续片段时, sum会加一次1。
  4. group by id, flag, 然后求出每个group的最大和最小日期,使用“最大日期 - 最小日期+1” ,就是连续登录连段的连续登录天数,记为cont_day
  5. 再group by id, 求最大的cont_day, 就是答案。
select id, max(cont_day) as max_cont_day
from
(
  select id, flag, max(time), min(time), datediff(max(time), min(time))+1 as cont_day
  from
  (
    select id, time, pre_date, diff, sum(diff) over(partition by id order by time) as flag
    from
    (
      select id, time ,pre_date, if(datediff(time, pre_date) > 2, 1, 0)  as diff
      from
      (
        SELECT 
          id, time,
          lag(time,1,'1970-01-01') over(partition by id order by time) as pre_date
        from log
      ) t0
    ) t1
  ) t2
  group by id, flag
) t3
group by id
参考:
  1. 方法二参考:SQL高频面试题:求最大连续登录天数,间隔n天内都可以算做连续登录_sql 最大连续登录次数-CSDN博客
  2. 方法二参考:SQL面试题挑战07:间隔连续问题(连续的升级版)_sql不间隔数字连续、数字间间隔几位连续-CSDN博客
  3. 更多方法可以见:数仓面试——连续登录问题进阶版-腾讯云开发者社区-腾讯云

你可能感兴趣的:(SQL: 求连续登录天数,间隔1天也算作连续)