用到的知识点:lead窗口函数,date_sub日期函数,case when end语句,取余是%,向下取整floor函数,group/having/order可以用别名
step1:统计每个用户在2021年7月7日到2021年10月31日的的登录情况,并按照登录日期排序。
with t1 as(
select distinct uid
,date(in_time) as in_day
,date_format(in_time,"%Y%m") as in_month
,row_number() over(partition by uid order by date(in_time)) as irank
from tb_user_log
where sign_in = 1 and artical_id = 0
and date(in_time) between '2021-07-07' and '2021-10-31')
解释:
1️⃣distinct保证(uid,in_day,in_month,irank)四个的组合是唯一的,保证一个用户在一天只有一条记录
2️⃣在这种情况下使用row_number/rank/dense_rank是完全一样的,因为每条记录都不同;
3️⃣in_month字段存在是为了帮助我们取出每个月签到的金币。
step2:统计每个用户在每个月的连续登录情况
with t2 as(
select uid,in_month, date_sub(in_day, interval irank day) as temp
,count(*) as days
from t1
group by uid, temp, in_month)
解释:
1️⃣连续登录判断依据:date_sub(in_day, interval irank day)是相同的,这也就是我们在第一步对登录日期进行排序➕第二步按照辅助列temp进行分组的原因
step3:统计每个用户在每个月获得金币的情况
select uid,in_month,
sum(case
when days%7 in (1,2) then floor(days/7)*15 + days%7
when days%7 in(3,4,5,6) then floor(days/7)*15 + days%7 + 2
else floor(days/7)*15 end) as coin
from t2
group by uid, in_month
order by in_month,uid
解释:
1️⃣在第二步已经统计出每个月的连续登录天数时,我们就可以按照金币获得规则算出每个用户每个月获得金币了。
使用case when语句,对连续登录天数days%7进行判断(⚠️不是对days进行判断,因为七天一个循环)
2️⃣计算金币时也要额外小心,连续登录7天获得15个金币,所以首先是floor(days/7)*15;其次根据days%7的不同进入不同的分支。
完整代码如下:
select uid,in_month,
sum(case
when days%7 in (1,2) then floor(days/7)*15 + days%7
when days%7 in(3,4,5,6) then floor(days/7)*15 + days%7 + 2
else floor(days/7)*15 end) as coin
from(
select uid,in_month, date_sub(in_day, interval irank day) as temp
,count(*) as days
from(
select distinct uid, date(in_time) as in_day,date_format(in_time,"%Y%m") as in_month
,row_number() over(partition by uid order by date(in_time)) as irank
from tb_user_log
where sign_in = 1 and artical_id = 0
and date(in_time) between '2021-07-07' and '2021-10-31'
) as t1
group by uid, temp, in_month) as t2
group by uid, in_month
order by in_month,uid



京公网安备 11010502036488号