首页 > 试题广场 >

最长连续登录天数

[编程题]最长连续登录天数
  • 热度指数:88214 时间限制: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 回复(5)
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 回复(9)
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 回复(1)
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 回复(10)
#抄的评论区大佬的,看了好几遍才看懂
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 回复(2)

AI可真聪明

步骤分析

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

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

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

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

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

发表于 2025-05-17 13:08:47 回复(2)
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)
# 你正在搭建一个用户活跃度的画像,其中一个与活跃度相关的特征是“最长连续登录天数”, 请用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)
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 CTE_1 AS (
SELECT
user_id,
fdate,
ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY fdate) AS rn
FROM tb_dau
WHERE fdate BETWEEN '2023-01-01' AND '2023-01-31'
),
CTE_2 AS(
SELECT
user_id,
COUNT(*) AS consec_days
FROM CTE_1
GROUP BY user_id, DATE_SUB(fdate, INTERVAL rn DAY)
)
SELECT
user_id,
MAX(consec_days) AS max_consec_days
FROM CTE_2
GROUP BY user_id

发表于 2025-12-17 16:39:06 回复(0)
搞了半天是要输出每一个用户分别最长连续登录了几天……然而你需求没说清楚+示例只给一个用户,不知道还以为你是要输出连续登录时间最长的用户的id及其天数
发表于 2025-09-25 14:55:59 回复(0)
```
WITH dis_user AS(
    SELECT
        DISTINCT user_id, fdate
    FROM tb_dau
    WHERE fdate BETWEEN "2023-01-01" AND "2023-01-31"
),
ranking_user AS(
    SELECT
        user_id,
        fdate,
        ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY fdate) AS ranking
    FROM dis_user
),
for_gr_user AS(
    SELECT
        user_id,
        fdate,
        DATE_SUB(fdate, INTERVAL ranking DAY) AS gr_key
    FROM ranking_user
),
gr_user AS(
    SELECT
        user_id,
        gr_key,
        COUNT(*) AS consec_days
    FROM for_gr_user
    GROUP BY user_id, gr_key
)
SELECT
    user_id,
    MAX(consec_days) AS max_consec_days
FROM gr_user
GROUP BY user_id
ORDER BY user_id

发表于 2025-09-20 23:53:46 回复(0)
with a as (select *,
    subdate(fdate, ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY fdate)) as newdate
from tb_dau)

select user_id, max(consec_days) max_consec_days
from(
select user_id, count(*) as consec_days
from a
group by user_id, newdate) b
group by user_id
发表于 2025-09-16 14:25:49 回复(0)
SELECT
    user_id,
    max(cnt) as max_consec_days
from
    (select
        t.user_id,
        date_sub(t.fdate,interval t.rk day)as 日期差,
        count(*) cnt
    from(
        SELECT
            user_id,
            fdate,
            row_number()over(partition by user_id order by fdate asc) rk
        FROM tb_dau
        WHERE fdate between '2023-01-01' and '2023-01-31'
        )t
    group by 日期差,t.user_id
    )sub
group by user_id;
发表于 2025-09-01 11:50:46 回复(0)
# 这个题的逻辑是,连续登录的日期减去递增的数字会得到相同的值,例如1月2号,1月3号,1月4号分别减去1,2,3,均得到1月1号,利用这个原理再将减完后相同日期的进行分组,计算数量,就得到连续登陆的天数。用max函数取最大值即可。

select user_id, max(t2.a2) max_consec_days
from(
select user_id, count(a1) a2
from(
select user_id, date_sub(fdate, interval
row_number()over(partition by user_id order by fdate) day) a1
from tb_dau
group by user_id, fdate
) t1
group by user_id, t1.a1
) t2
group by user_id
发表于 2025-07-31 18:59:46 回复(0)
with tmp0 as(select a.fdate,a.user_id,b.fdate as hdate,b.user_id as huser_id,row_number() over(partition by a.fdate,a.user_id order by b.fdate asc) as xianzaiduoshaoge,datediff(b.fdate,a.fdate) as date_diff from tb_dau a left join tb_dau b on b.fdate>=a.fdate and b.user_id=a.user_id where a.fdate between '2023-01-01' and '2023-01-31'),
tmp1 as (select * from tmp0 where date_diff+1=xianzaiduoshaoge)
select a.user_id,max(xianzaiduoshaoge) as max_consec_days from tmp1 a group by a.user_id  order by a.user_id asc
做了半个小时。。。。抓耳挠腮10分钟后确定思路是左连接,然后再右表中进行分组,判断连续的依据是datediff=目前是该组中第几个+1(例如01-01这一组,01-02是该组第二个,datediff+1=2,因此是连续的,01-04是第三个,但是datediff+1=4,因此不连续了)。每个日期都会计算,因此不必担心漏算。
因为一些小错误导致自己认为思路是错的。。。。。包括但不限于忘记加日期约束、写错 on条件。。。。。
另外,有没有佬可以告知一下:笔试的时候可以一直运行(不是提交)看结果吗?
发表于 2025-07-21 22:08:26 回复(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)
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)