WITH t1 AS(
    SELECT
        DISTINCT uid,
        sign_in,
        artical_id,
        DATE(in_time) AS dt,
        DENSE_RANK() OVER(PARTITION BY uid ORDER BY DATE(in_time))  AS day_num
    FROM tb_user_log
    WHERE sign_in = 1 AND artical_id = 0 AND DATE(in_time) BETWEEN '2021-07-07' AND '2021-10-31'
),

t2 AS(
SELECT
    uid,
    DATE_FORMAT(dt, '%Y%m') AS mon,
    DENSE_RANK() OVER(PARTITION BY DATE_SUB(dt, INTERVAL day_num DAY) ORDER BY dt) % 7 AS continue_day
FROM t1
)

SELECT
    uid,
    mon AS month,
    SUM(
        CASE
            WHEN continue_day = 3 THEN 3
            WHEN continue_day = 0 THEN 7
            ELSE 1 
        END
    ) AS coin
FROM t2 
GROUP BY uid, mon
ORDER BY mon, uid

这题的关键在于如何判断日期是否连续。

可以对日期进行排序,如果一段日期是连续的,则日期 - 排序序号的天数得到的结果应该是相同的,比如7月2、3、4、5号分别减去1,2,3,4天,都等于7月1号。所以可以使用日期 - 排序序号对数据进行分类,分在同一类别之下的即为连续的一段日期。

再使用DENSE_RANK()得到日期是“连续的第几天”,用DENSE_RANK()除以7的余数来处理7天的周期性(每7天重新开始计算),加上CASE WHEN函数对第3、7天作特殊处理,最后使用SUM聚合得到答案。