首页 > 试题广场 >

最长连续登录天数

[编程题]最长连续登录天数
  • 热度指数:50785 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
你正在搭建一个用户活跃度的画像,其中一个与活跃度相关的特征是“最长连续登录天数”, 请用SQL实现“2023年1月1日-2023年1月31日用户最长的连续登录天数”
登陆表 tb_dau:
fdate user_id
2023-01-01 10000
2023-01-02 10000
2023-01-04 10000
输出:
user_id max_consec_days
10000 2
示例1

输入

drop table if exists tb_dau;
create table `tb_dau` (
    `fdate` date,
    `user_id` int
);
insert into tb_dau(fdate, user_id)
values 
('2023-01-01', 10000),
('2023-01-02', 10000),
('2023-01-04', 10000);

输出

user_id|max_consec_days
10000|2

说明

id为10000的用户在1月1日及1月2日连续登录2日,1月4日登录1日,故最长连续登录天数为2日

备注:
MySQL中日期加减的函数
日期增加 DATE_ADD,例:date_add('2023-01-01', interval 1 day) 输出 '2023-01-02'
日期减少 DATE_SUB,例:date_sub('2023-01-01', interval 1 day) 输出 '2022-12-31'
日期差 DATEDIFF,例:datediff('2023-02-01', '2023-01-01') 输出31
抛开题目来讲,在表的设计里最初就应该有 “当前连续登录天数”这个字段
发表于 2024-08-27 17:39:06 回复(1)
select user_id, max(consec_days) max_consec_days
from
(select user_id, count(startday) consec_days
from
(select user_id, 
date_sub(fdate, interval (dense_rank() over (partition by user_id order by fdate)) day) startday
  from tb_dau
 where year(fdate) = 2023 and month(fdate) = 1
) t1
group by user_id, startday
) t2
group by user_id
在最内层表中,利用日期减去该日期本身按正序排序后的ranking。
如果一段日期为连续的,他们减去排序后的日期所得的起始日期相同。
发表于 2024-08-09 15:23:33 回复(7)
WITH t1 AS (
    SELECT 
        user_id,
        fdate,
        ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY fdate) AS 日期排序,
        DATE_SUB(fdate, INTERVAL ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY fdate) DAY) AS 初始日期
    FROM tb_dau
    WHERE fdate BETWEEN '2023-01-01' AND '2023-01-31'
),

-- 第二步:计算每个“初始日期”对应的连续登录天数
t2 AS (
    SELECT
        user_id,
        初始日期,
        MAX(日期排序) - MIN(日期排序) + 1 AS 连续登录天数
    FROM t1
    GROUP BY user_id, 初始日期
)

-- 第三步:获取每位用户的最长连续登录天数
SELECT
    user_id,
    MAX(连续登录天数) AS max_consec_days
FROM t2
GROUP BY user_id;
发表于 2024-11-06 21:01:15 回复(0)
select
user_id
,max(num) max_consec_days
from
    (select
    user_id
    ,date_sub(fdate, interval r day) datesub
    ,count(1) num
    from
        (select
        user_id
        ,fdate
        ,row_number()over(partition by user_id order by fdate) r
        from tb_dau
        where fdate between '2023-01-01' and '2023-1-31') a
    group by 1,2
    ) b
group by 1

发表于 2024-09-11 22:36:14 回复(9)
#抄的评论区大佬的,看了好几遍才看懂
with t1 as(
    select user_id, count(continday) as consec_days
    from
    (
        select user_id, 
        # data_sub函数
        # 用登陆日期-连续递增的数字(排序的位次),
        # 如果日期连续,就会产生相同的结果
        date_sub(fdate, interval (
            dense_rank() 
            over (partition by user_id order by fdate)
        ) day
        ) continday
        from tb_dau
        where year(fdate) = 2023 and month(fdate) = 1
    ) t2
    # 对计算结果进行分组,相同的在一组,表示连续登录
    group by user_id, continday
)

select user_id, max(consec_days) as max_consec_days
from t1
group by user_id

发表于 2024-09-05 16:17:41 回复(1)
# 你正在搭建一个用户活跃度的画像,其中一个与活跃度相关的特征是“最长连续登录天数”, 请用SQL实现“2023年1月1日-2023年1月31日用户最长的连续登录天数”


with tmp as (
    select
user_id,
tmp_date,
count(*) as cnt
from(select
user_id,
date_sub(fdate,interval rn day) as tmp_date
from (select
*,row_number() over(partition by user_id order by fdate ) as rn
from tb_dau) a ) b
group by 1,2
)
select
user_id ,
max(cnt) as max_consec_days
from tmp
group by 1;

-- 日期减去日期的对应排序,结果等于同一天,然后对同一天进行计数 比如:
#   日期          排序rn
# '2023-01-01'  1
# '2023-01-02'  2

# date_add('2023-01-01', interval 1 day) 输出 '2022-12-31'
# date_add('2023-01-02', interval 2 day) 输出 '2022-12-31'
# 对'2022-12-31',进行计数即可
发表于 2024-08-10 11:40:09 回复(1)
with
    t1 as (
        select distinct
            user_id,
            fdate
        from
            tb_dau
        where
            fdate >= '2023-01-01'
            and fdate <= '2023-01-31'
    ),
    t2 as (
        select
            user_id,
            fdate,
            rank() over (
                partition by
                    user_id
                order by
                    fdate
            ) as rn
        from
            t1
    ),
    t3 as (
        select
            user_id,
            fdate,
            date_sub (fdate, interval rn day) flag_date
        from
            t2
    ),
    t4 as (
        select
            user_id,
            count(*) total
        from
            t3
        group by
            user_id,
            flag_date
    )
select
    user_id,
    max(total) as max_consec_days
from
    t4
group by
    user_id

发表于 2024-08-09 18:21:30 回复(0)

AI可真聪明

步骤分析

  1. 去重处理:确保每个用户每天的登录记录唯一。

  2. 生成序号:为每个用户的登录日期按顺序编号。

  3. 计算连续组标识:用登录日期减去序号,相同结果的日期属于同一连续组。

  4. 统计每组连续天数:按用户和连续组分组,计算每组的连续天数。

  5. 取最大值:对每个用户,取所有连续组中的最大天数。

发表于 2025-05-17 13:08:47 回复(0)
select 
    user_id,
    max(co) max_consec_days
from (
    select
        user_id,
        count(rn) co
    from (
        select 
            fdate,
            user_id,
            row_number()over(partition by user_id order by fdate) rn,
            date_sub(fdate,interval row_number()over(partition by user_id order by fdate) day) ds
        from tb_dau
    ) a
    group by user_id,ds
) b
group by user_id;

发表于 2024-12-20 10:29:18 回复(0)
with tmp as (
    select 
    IFNULL(DATEDIFF(next,fdate)=1,0) as diff,
    row_number() over(partition by user_id order by fdate) as eday,
    user_id
from(
select
    fdate,
    user_id,
    lead(fdate,1,NULL) over(partition by user_id order by fdate) as next
from tb_dau) t1
)

select
    user_id,
    MAX(eday-last) as max_consec_days
from(
select
    lag(eday,1,0) over(partition by user_id order by eday rows 1 preceding) as last,
    user_id,
    eday
from tmp
where diff=0
)t1
group by user_id
发表于 2025-04-29 22:51:05 回复(0)
MySQL 用户变量编程解法。
最后记得Cast 显式做类型转换,否则默认认为是字符串类型。
# Write your MySQL query statement below

WITH
t0 as (
    select distinct fdate as login_date, user_id as id
    from tb_dau
    where fdate between '2023-01-01' and '2023-01-31'
)
,
t1  AS (
    SELECT
        #------------只需要修改里面的逻辑就行。注意语句是“顺序执行”的-------------------------------
        login_date,
        id,


        (case when login_date = @prev_date + INTERVAL 1 DAY AND id = @prev_author_id then @consec_days := @consec_days + 1
        when login_date = @prev_date AND id = @prev_author_id then @consec_days := @consec_days 
        else @consec_days := 1 end)  AS consec_days,


        @prev_date := login_date,
        @prev_author_id := id
        #-------------只需要修改里面的逻辑就行。注意语句是“顺序执行”的------------------------------
    FROM
        (SELECT @prev_date := NULL, @prev_author_id := NULL, @consec_days := 1) vars,
        (SELECT login_date, id FROM t0 ORDER BY id , login_date) ordered_dates
)


SELECT id as user_id, max((CAST(consec_days AS UNSIGNED))) as max_consec_days
from t1
group by id 





发表于 2025-04-15 13:43:52 回复(0)
WITH t1 as (
	select user_id,fdate,DATE_SUB(fdate,interval ROW_NUMBER() over(PARTITION by user_id ORDER BY fdate) day) as date_sub
	from tb_dau
),
t2 as (
SELECT user_id,count(*) day_sum from t1 GROUP BY user_id,date_sub
),
t3 as(
select user_id,day_sum,ROW_NUMBER() over(PARTITION by user_id ORDER BY day_sum desc) day_rank from t2
) 
SELECT user_id,day_sum as max_consec_days from t3 where day_rank =1
欢迎大家指正批评!
发表于 2024-09-30 19:39:44 回复(1)
select user_id,consecutive_days as max_consec_days
from 
(select user_id,consecutive_days,dense_rank()over(partition by user_id order by consecutive_days desc) as rk 
from 
(select user_id,min(fdate),max(fdate),count(*) as consecutive_days
from 
(select user_id,fdate,date_sub(fdate,interval rn day) as grp,rn
from 
(SELECT user_id,fdate,ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY fdate) AS rn
FROM tb_dau) as t1
) as t2
group by user_id,grp) as t3
) as t4
where rk =1 
group by user_id,consecutive_days

发表于 2024-08-14 14:57:39 回复(0)
select user_id,max(max_consec_days) max_consec_days
from (
select start_day,user_id,count(1) max_consec_days
from (
    select user_id
    ,fdate 
    ,date_sub(fdate,interval row_number()over(partition by user_id order by fdate) day) start_day
    from tb_dau
    where fdate between '2023-01-01' and '2023-01-31'
   )a 
group by start_day,user_id
)t2
group by user_id

发表于 2025-06-18 21:05:29 回复(0)
# 多层嵌套是其次,最主要的是  日期排序之后与自身排名的差 相等的值 该组值的计数为连续登录的天数
with tabel1 as
(select
user_id, fdate, row_number()over(partition by user_id order by fdate) num
from tb_dau
where fdate between '2023-01-01' and '2023-1-31'),
tabel2 as
(select
user_id, fdate, num, date_sub(fdate, interval num day) ds
from tabel1
),
tabel3 as
(select user_id, ds, count(*) pn
from tabel2
group by user_id, ds)
select
user_id,
pn max_consec_days
from
(select
user_id, pn, row_number()over(partition by user_id order by pn desc) r_n
from tabel3) as p
where r_n = 1
发表于 2025-06-18 19:04:17 回复(0)
with a as 
(select distinct fdate,user_id,row_number() over(partition by user_id order by fdate) ranking from tb_dau),
b as
(select *,date_sub(fdate, interval ranking day) df from a),
c as
(select user_id, count(df) consec_days from b group by user_id,df)
select user_id,max(consec_days) max_consec_days from c group by user_id

发表于 2025-06-18 14:15:48 回复(0)

select user_id,max(day_count) as max_consec_days
from(select user_id,count(1) as "day_count"
from(select user_id,date_sub(fdate,interval row_num day)as "day"
from(select user_id,fdate,
    row_number()over(partition by user_id order by fdate asc) as "row_num"
from (select distinct fdate,user_id
from tb_dau)as t
where year(fdate)=2023 and month(fdate)=1)as t1)as t2
group by user_id,day)t3
group by user_id

发表于 2025-06-16 18:24:53 回复(0)
select user_id,max(连续登录天数) max_consec_days
from
(select user_id,count('初始日期') 连续登录天数
from
(select user_id,fdate,row_number() over(partition by user_id order by fdate) as 日期排序,
date_sub(fdate, interval row_number() over(partition by user_id order by fdate) dayas 初始日期#得到“伪日期列-date2,若连续登录,date2应相同
from tb_dau
where fdate between '2023-01-01' and '2023-01-31') as t1
group by user_id, 初始日期) as t2
group by user_id

发表于 2025-06-13 21:28:53 回复(1)
select user_id,max(sd) max_consec_days
from
(select user_id,min(fdate),max(fdate),count(1) as sd
from
(select user_id,fdate,fdate-row_number() over (partition by user_id) sds
from tb_dau) a
group by user_id,sds) b
group by user_id
发表于 2025-06-12 17:36:26 回复(0)
select user_id,max(rk) max_consec_days from
(select user_id,fdate,dense_rank() over(partition by user_id, time_len order by fdate ) rk from
(select user_id,fdate,date_sub(fdate,interval rk day) time_len from
(select fdate,user_id,dense_rank() over(partition by user_id order by fdate) rk from tb_dau) t) t1
where fdate between '2023-01-01' and '2023-01-31') a
group by user_id
发表于 2025-06-10 21:23:10 回复(0)