题解 | #连续签到领金币#
连续签到领金币
https://www.nowcoder.com/practice/aef5adcef574468c82659e8911bb297f
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聚合得到答案。