一、题目
有用户登录记录,已经按照日期去重。求近三十天,用户连续登录超过3天的次数,一直连续登录算一次,有间隔然后重新计算次数, 要求不能用开窗。
数据样例如下:

二、思路
这是一个连续问题:连续问题的解决思路是找到日期和升序序号差值相同的记录,相同则表示日期连续,不同则日期不连续。题目强调不能使用开窗函数,可以借助collect_list和posexplode获取升序序号。
看一下具体实现步骤:
1)按照user_id, login_date 排序,保证同一个用户的登录日期是升序的
2)使用collect_list保存同一个userid的登录日期
3)使用lateral view posexplode膨胀数据,同时为每个日期打上升序序号
4)使用date_sub计算减去序号后的差值日期:如果连续则差值日期相同
5)计算每个userid、差值日期的数量,这里要求数量>3
6)最后统计连续登录3天以上的次数

三、解答
with tab_idx_detal as (
-- 将每个用户的登录日期按升序打标
select
user_id,
log_dt,
idx
from (
-- 将每个用户的登录日期做成list,用于后续按升序打标
select
user_id,
collect_list(login_date) log_date_lsit
from (
select
*
from use_login_detail
order by user_id,
login_date
) t11
group by user_id
) t21
lateral view posexplode(log_date_lsit) tab as idx, log_dt
)
select
user_id,
count(res_dt) cnt
from (
select
user_id,
res_dt,
count(*) cnt
from (
-- 如果res_dt相同则表示这几天连续登录
select
user_id,
log_dt,
idx,
date_sub(log_dt, idx) res_dt -- 减去序号后的日期
from tab_idx_detal
) t11
group by user_id,
res_dt
) t21
where cnt > 3
group by user_id结果:

数据
# 建表
--建表语句
create table use_login_detail
(
user_id string, -- 用户id
login_date string -- 登陆日期
) comment '用户登录记录表'
stored as parquet;
--插入数据
insert into table use_login_detail values
('001','2024-07-03'),
('001','2024-07-04'),
('001','2024-07-05'),
('001','2024-07-06'),
('001','2024-07-12'),
('001','2024-07-13'),
('001','2024-07-17'),
('001','2024-07-18'),
('001','2024-07-19'),
('001','2024-07-20'),
('001','2024-07-21')
('002','2024-07-17'),
('002','2024-07-18'),
('002','2024-07-19'),
('002','2024-07-20'),
;注:题目获取自网络
评论