思路跟大家是一样的,就不放图解啦;唯一好处就是不断嵌套的写法:
1. 很好理解(所有新增列,都源于题目一个表)
2. 没有重复出现的语句
3. 方便一步步检验
SELECT uid,DATE_FORMAT(sign_dt,"%Y%m") month,SUM(coin_cnt) coin
FROM
    (
    SELECT uid,sign_dt, #求得某个uid在某天签到时候获得的金币数 
            CASE WHEN rank_day % 7 = 3 THEN 3
                 WHEN rank_day % 7 = 0 THEN 7
                 ELSE 1 END coin_cnt # coin列,表示每次签到增加的金币数
    FROM 
        (
        SELECT uid,sign_dt,ROW_NUMBER()OVER(PARTITION BY uid,date_group ORDER BY sign_dt) rank_day 
                            # 在这个签到周期内排序,求得第几天
        FROM
            (
            SELECT uid,sign_dt,DATE_SUB(sign_dt,INTERVAL sign_cnt DAY) date_group 
                                # 以这个日期分组;一组一个签到周期
            FROM 
                (
                SELECT DISTINCT uid, DATE(in_time) sign_dt, #没有group by时,distinct一下保证唯一性
                       ROW_NUMBER()OVER(PARTITION BY uid ORDER BY DATE(in_time)) sign_cnt
                FROM tb_user_log
                WHERE  artical_id = 0 AND sign_in = 1
                AND DATE(in_time) BETWEEN "2021-07-07" AND "2021-10-31"
                ) t1
            ) t2
        ) t3
    ) t4
GROUP BY uid, DATE_FORMAT(sign_dt,"%Y%m")
ORDER BY month, uid