近 30 天每日活跃用户数
LeetCode 1141 · 日期范围、去重计数
面试怎么回答
WHERE activity_date BETWEEN 截止日 - 29 天 AND 截止日,按天 COUNT(DISTINCT user_id)。我会强调「近 30 天含当天」是 29 天前到今天的闭区间,不要用「减一个月」近似,大小月会出错。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
活动表记录用户的会话行为和日期。统计截至 2019-07-27(含)的 30 天内,每天的活跃用户数(当天有任意活动即算活跃),没有活跃用户的日期不用输出。
表结构
- Activity:user_id、session_id、activity_date、activity_type;没有主键,可能有重复行
思路
按日期范围过滤后,按天分组 COUNT(DISTINCT user_id)。原解法用「减 1 个月」当 30 天,在 6 月到 7 月之间碰巧相等(6 月有 30 天),换个月份就会多一天或少一天;直接写 29 天的区间更准确,也要加上不超过截止日的上界。
参考解法
select activity_date day,count(distinct user_id) active_users
from Activity
where activity_date > date_add('2019-07-27',INTERVAL -1 MONTH)
group by activity_date
另一种写法:明确写出 30 天的闭区间
SELECT activity_date AS day, COUNT(DISTINCT user_id) AS active_users
FROM Activity
WHERE activity_date BETWEEN DATE_SUB('2019-07-27', INTERVAL 29 DAY) AND '2019-07-27'
GROUP BY activity_date
易错点
- 「1 个月」不等于「30 天」,跨大小月时会出错。
- 只写下界不写上界,截止日之后的数据也会被统计进来。