MySQL过程式编程,case when嵌套,差分(自联结完成),PERIOD_DIFF求月份差

发布时间 2023-03-23 12:08:42作者: yhm138

题目地址

https://www.nowcoder.com/practice/aef5adcef574468c82659e8911bb297f

代码

# 还是过程式编程吧,否则万一签到奖励规则变了,SQL代码你根本不知道怎么改

# Keep in mind that MySQL user variables are deprecated since MySQL 8.0.13, so using window functions might be a better approach for future-proofing your query.



# 活动规则:(设计得很好,下次不要设计了)
# 从2021年7月7日0点开始,用户每天签到可以领1金币,并可以开始累积签到天数,连续签到的第3、7天分别可额外领2、6金币。
# 每连续签到7天后重新累积签到天数(即重置签到天数:连续第8天签到时记为新的一轮签到的第一天,领1金币)

with t1 as(
    select *,date(date_format(in_time,"%Y-%m-%d")) as signin_date from tb_user_log where sign_in=1 and artical_id=0 and in_time >= date("2021-07-07 00:00:00") and  in_time<date("2021-11-01 00:00:00")
)
,
signin_dates AS (
    SELECT
        signin_date,
        uid,
        
        # ----只需要改动这里的逻辑,其他不要动----------
        IF(signin_date = @prev_date + INTERVAL 1 DAY AND uid = @prev_uid 
        AND @consec_days <> 7
        , @consec_days := @consec_days + 1, @consec_days := 1) AS consec_days,

        (case when uid = @prev_uid then
             (case when signin_date = @prev_date + INTERVAL 1 DAY then 
                (case when @consec_days=3 then @coin := @coin + 1+2
                      when @consec_days=7 then @coin := @coin + 1+6
                      else @coin := @coin + 1 
                end)
                   else @coin := @coin + 1
             end)
             else 
                @coin := 1 
        end) AS coin,
        # ----只需要改动这里的逻辑,其他不要动-----------


        @prev_date := signin_date,
        @prev_uid := uid
    FROM
        (SELECT @prev_date := NULL, @prev_uid := NULL, @consec_days := 1 , @coin := 1) vars,
        (SELECT signin_date, uid FROM t1 ORDER BY uid, signin_date) ordered_dates
)
,
# 每个用户每日金币持有数
`每个用户每日金币持有数` as(
select signin_date,uid,coin,
row_number() over(partition by uid,date_format(signin_date,"%Y-%m") order by signin_date desc) as rn
from signin_dates
)
,
# 每个用户每月底金币持有数
`每个用户每月底金币持有数` as(
select uid,
date_format(signin_date,"%Y%m") as month,
cast(coin as unsigned) as coin
from `每个用户每日金币持有数`
where rn  = 1 
order by month , uid   
)

# 自联结求一下每月拿了多少金币
select 
tmp1.uid,tmp1.month,
ifnull(tmp1.coin-tmp2.coin ,tmp1.coin)
from `每个用户每月底金币持有数` tmp1
left join `每个用户每月底金币持有数` tmp2
on tmp1.uid=tmp2.uid and  PERIOD_DIFF(tmp2.month,tmp1.month)<0