题解 | #连续签到领金币#
连续签到领金币
http://www.nowcoder.com/practice/aef5adcef574468c82659e8911bb297f
# 大厂的题目做了十二道了,平均下来每道题算上我复盘的时间都有一个小时左右,和之前的进阶题目很大的区别就是业务性很强
# 有很多要结合窗口函数找排序、找连续签到、登录天数、完播率等等之类的题目,很多我觉得都很绕,但是看完题解,或者看完别人的思路
#就觉得很妙,感觉自己很难想到这种做法,大多都是会做出一个差不多具有最终表需要的数据表,但是到取数或者做表的时候,有些关键的内容
# 自己往往就不懂该怎么去做出来,这时候就要去翻看题解了,好多知识点还没能熟练掌握,感觉需要不断的复习,甚至背诵下题目的解题思路
# 才能较好的掌握这道题目的精髓!
# 想这道题,就不知道该怎么样去找出连续的天数 和断开的天数。
select uid,
date_format(dt,'%Y%m') as month,
sum(co) as coin
from
### 第五步:就是在这个有用户id、时间、某天的时间对应获得的硬币数的新表中去统计出题目想要的内容
(
### 第四步,给上一步中的连续签到的同学打上获得银币的标签,也就是依据他签到的第x天来获得活动相应给出的硬币
select uid,
dt,
if(lxdldts % 7 = 3 ,3,
if(lxdldts % 7 = 0,7,1)) as co
from
(
### 第三步,就是给那些断了天数重新排序,这样方便后续给他们打上标签,其中这个排序就很有意思了,我一开始是做错了没有分足够多的类,首先要按人来分类,其次中要的一点是需要按照第二步中找出来的断续人的天数来分类,也就是dt_cut,这样就可以把他第二次甚至第三次重新开始连续签到的时间给排序出来。
select *,
row_number() over (partition by uid,dt_cut order by dt) as lxdldts
from
(
### 第二步.这一步是找出连续的签到天数和不连续的签到天数,这步很有意思。因为排名是连续的,所以如果用户的签到天数如果没有连续的话,那么得到的dt_cut会和之前的dt_cut是不相等的,那么再重新排序一次就可以判断出他的日期是不是连续的了
select *,
date_sub( dt , interval m day) as dt_cut
from
(
### 第一步 先将每个用户每次的登录都做一个排序 因为排序了就可以有标签,而这个标签刚好就可以判断用户登录了多少天,接下来就是判断用户的登录天数是不是连续的了
select uid,
date(in_time) as dt,
rank() over (partition by uid order by date(in_time)) as m
from tb_user_log
where artical_id =0 and sign_in = 1
having dt > '2021-07-06' and dt < '2021-11-01'
) p
)p2
)p3
)p4
group by uid,month
order by month,uid