HQL:连续签到_三种解决方案
表结构
/*
table_name : user_log
fields:
1.uid
2.artical_id 视频id
3.in_time 进入时间
4.out_time 离开时间
5.sign_in 是否签到
几条表数据
考察到的知识点
-
date_sub()
-
datediff()
-
last_value(field,true/false) over()
-
lag(field) over()
-
sum(),count()
-
对于开窗函数的界限问题
/* 1.不指定partition by 默认全表 2.不指定order by 默认全表,可用于sum()场景 3.不使用窗口句子 1.不适用order by 默认全表 2.使用order by,默认第一行到当前行
思路
第一步肯定是先找出所有签到的数据
等差法
然后我们以用户分组,in_time排序,然后进行排序,如果连续,那么in_time – 排序的值必定得到一个相等的值,然后我们再根据 差值+uid 分组即可得到连续的值
累加求和法
可以先获取每条数据上一条数据的in_time值,然后相减,等差1则置为0,否则置为1,然后我们在通过一个开窗函数进行累加 最后再通过 uid+累加值分组即可
填充法
填充法也是要先获取上一条记录然后做差,相同为null,因为第一天签到无法获取上一天,那么我们可以特殊处理,如果为null的话,值设置为in_time 然后通过last_value() over() 填充,
方案一:等差法
/*
select
uid,
flag,
count(1)
from(
select
uid,
date_format(in_time,'yyyy-MM-dd'),
date_sub(date_format(in_time,'yyyy-MM-dd'),rank() over(partition by uid,order by in_time asc)) flag
from user_log
where sign_in=1
)t
group by uid,flag
方案2 累加求和法
/*
select
uid,
mark,
count(1)
from(
select
uid,
sum(ck) over(partition by uid order by in_time) mark
from(
select
uid,
in_time,
if(in_time = null ,1,if(datediff(in_time,flag)=1,0,1)) ck
from(
select
uid,
date_format(in_time,'yyyy-MM-dd') in_time,
lag(date_format(in_time,'yyyy-MM-dd')) over(partition by uid,order by in_time asc)flag
from user_log
where sign_in=1
)t
)t2
)t3
group by uid,mark
方案三 填充法
select
uid,
mark,
count(1)
from(
select
uid,
last_value(ck,true) over(partition by uid,order by in_time) mark
from(
select
uid,
in_time,
if(in_time = null ,in_time,if(datediff(in_time,flag)=1,null,in_time)) ck
from(
select
uid,
date_format(in_time,'yyyy-MM-dd') in_time,
lag(date_format(in_time,'yyyy-MM-dd')) over(partition by uid,order by in_time asc)flag
from user_log
where sign_in=1
)t
)t2
)t3
group by uid,mark
版权声明:本文为C_x_330原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。