需求 : 计算每个用户最大的连续登录天数,可以间隔一天。解释:如果一个用户在 1,3,5,6 登录游戏,则视为连续 6 天登录
-- 数据准备
-- DDL
create table test2 (
`user_id` string comment '用户id',
`login_date` string comment '登入日期',
`login_status` string comment '登入状态(1:成功,2:异常)')
comment '用户登入记录表'
row format delimited fields terminated by '\t'
lines terminated by '\n' stored as orc;
-- DML
insert overwrite table test2
select '1001' as id,'2021-12-12' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2021-12-20' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-02-10' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2021-12-20' as occur_date,'0' as lowcarbon union all
select '1002' as id,'2021-12-12' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2021-12-13' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2021-12-13' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2021-12-13' as occur_date,'1' as lowcarbon union all
select '1002' as id,'2021-12-14' as occur_date,'0' as lowcarbon union all
select '1001' as id,'2021-12-14' as occur_date,'1' as lowcarbon union all
select '1002' as id,'2021-12-15' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2021-12-15' as occur_date,'1' as lowcarbon union all
select '1003' as id,'2021-12-15' as occur_date,'0' as lowcarbon union all
select '1003' as id,'2021-12-16' as occur_date,'1' as lowcarbon union all
select '1003' as id,'2021-12-17' as occur_date,'1' as lowcarbon union all
select '1003' as id,'2021-12-18' as occur_date,'1' as lowcarbon union all
select '1003' as id,'2021-12-29' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-01-01' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-01-01' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-01-01' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-01-03' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-01-05' as occur_date,'1' as lowcarbon union all
select '1001' as id,'2022-01-06' as occur_date,'1' as lowcarbon union all
select '1003' as id,'2021-12-19' as occur_date,'1' as lowcarbon ;
-- 数据说明
-- 某游戏公司记录的用户每日登录数据
-- 每天每天可能有多次登入记录
-- 分析思路
-- 对每条记录添加标签
1. 当前记录是否连续(if_contine)
思考 : 怎样判断当前记录是否为连续记录
排序后,与前一条记录日期或后一条记录日期 差值是否为 1或者2
2. 为同一用户多段连续记录分组
contine_group
user_id login_date lead_days lag_days if_contine contine_group
1001 2021-12-12 1 NULL 0 0
1001 2021-12-13 1 1 0 0
1001 2021-12-14 1 1 0 0
1001 2021-12-15 5 1 0 0
1001 2021-12-20 12 5 1 1
1001 2022-01-01 2 12 0 1
1001 2022-01-03 2 2 0 1
1001 2022-01-05 1 2 0 1
1001 2022-01-06 35 1 0 1
1001 2022-02-10 NULL 35 1 2
1002 2021-12-12 3 NULL 1 1
1002 2021-12-15 NULL 3 1 2
1003 2021-12-16 1 NULL 0 0
1003 2021-12-17 1 1 0 0
1003 2021-12-18 1 1 0 0
1003 2021-12-19 10 1 0 0
1003 2021-12-29 NULL 10 1 1
-- 查询结果
user_id max_contine_days
1001 6
1003 4
-- 执行sql
-- 执行sql
with t1 as (
-- 对基础数据排序,剔除登入失败记录
select
user_id
,login_date
from test2
where login_status = '1'
group by user_id
,login_date),
t2 as (
-- 对user_id分组,对login_date排序,获取当前行的 前一行和后一行
select
user_id
,login_date
,lead(login_date,1,login_date) over (partition by user_id order by login_date asc) as lead_login_date
,lag(login_date,1,login_date) over (partition by user_id order by login_date asc) as pre_login_date
,datediff(lead(login_date,1) over (partition by user_id order by login_date asc) , login_date) as lead_days
,datediff(login_date,lag(login_date,1) over (partition by user_id order by login_date asc)) as lag_days
from t1),
t3 as (
-- 根据 当前行和前一行和后一行的差值,判断当前行是否连续, 并对连续记录分组
select
user_id
,login_date
,lead_days
,lag_days
-- 是否连续 0:连续 1:不连续
,case when lead_days in (1,2) then 0
when lag_days in (1,2) then 0
else 1 end as if_contine
-- 对每个用户,不同连续阶段分组
,sum(
case when lead_days in (1,2) then 0
when lag_days in (1,2) then 0
else 1 end
) over (partition by user_id order by login_date asc) as contine_group
from t2),
t4 as (
-- 获取连续记录中的 最大连续天数
select
user_id
,contine_group
,datediff(max(login_date),min(login_date)) as contine_days
from t3
where if_contine = 0
group by user_id
,contine_group )
select
user_id
,max(contine_days) + 1 as max_contine_days
from t4
group by
user_id
;
-- 查询结果
user_id max_contine_days
1001 6
1003 4