订阅更新

近 30 天每日活跃用户数

SQL 实战 123 题 · 第 66 题 简单 约 2 分钟读完

LeetCode 1141 · 日期范围、去重计数

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

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 天」,跨大小月时会出错。
  • 只写下界不写上界,截止日之后的数据也会被统计进来。
刷题进度保存在当前浏览器