MySQL兼容5+/8+ 统计每日及对应日期前30天注册用户数
需求背景
现有users用户表,核心字段如下:
user_id:用户唯一标识created_at:时间戳类型,存储用户注册时间
需要实现两类统计:
- 按自然日统计当日新增注册用户数
- 对每个统计日期,同步计算该日期往前30天(含统计当日)的累计注册用户总数
要求最终SQL同时兼容MySQL 5.x、MySQL 8.x版本。
已实现的单场景SQL
每日注册用户数统计
SELECT DATE_FORMAT(date(created_at),'%d %M %Y') AS Days, COUNT(user_id) as Profiles FROM users GROUP BY YEAR(created_at), MONTH(created_at), DAY(created_at);
固定当前日期的近30天注册数统计
SELECT current_date(),COUNT(user_id) FROM users WHERE created_at >= NOW() - INTERVAL 30 DAY;
现有问题:上述第二个SQL固定以当前时间为基准计算30天累计值,需要将固定日期替换为第一个SQL生成的所有业务日期,逐日期计算对应时间窗口的累计注册量。
跨版本兼容实现方案
不依赖MySQL 8.0才支持的窗口函数,采用子查询预聚合+表关联的写法,可直接在MySQL 5.5+所有版本运行:
SELECT DATE_FORMAT(daily.reg_date, '%d %M %Y') AS Days, daily.daily_cnt AS Profiles, COUNT(u.user_id) AS last_30days_total FROM ( -- 预聚合得到所有有注册记录的日期、当日注册量 SELECT DATE(created_at) AS reg_date, COUNT(user_id) AS daily_cnt FROM users GROUP BY DATE(created_at) ) daily -- 关联用户表按时间窗口统计累计值 LEFT JOIN users u ON u.created_at >= daily.reg_date - INTERVAL 30 DAY AND u.created_at < daily.reg_date + INTERVAL 1 DAY GROUP BY daily.reg_date, daily.daily_cnt ORDER BY daily.reg_date;
实现说明
- 兼容性:未使用窗口函数、CTE等MySQL 8.0新增特性,所有语法均兼容MySQL 5.x全版本
- 性能优化:时间区间判断未对
created_at字段使用函数转换,可直接命中created_at字段上的索引,避免全表扫描 - 逻辑对齐:时间窗口范围与原单场景SQL完全一致,覆盖统计日期前30天0点至统计日期当日24点的所有注册记录,包含统计当日数据
- 逻辑简化:内层聚合使用
DATE(created_at)分组,与原SQL中按年、月、日分别分组的效果完全一致,写法更简洁
如果需要返回无注册记录的空日期,需要先生成连续自然日的日历表再关联统计,当前实现与原每日统计SQL逻辑对齐,仅返回存在注册行为的日期。
内容的提问来源于stack exchange,提问作者Aiha
相关产品推荐
相关产品推荐

