You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL按日期统计用户数:实现缺失日期返回0的方案

如何统计指定日期范围内的每日新增用户(含无数据日期返回0)

问题概述

你有一个user表,其中addtime字段为timestamp类型,希望按年、月、日分组统计每日新增用户数量。当前的查询仅返回有用户注册的日期数据,但你需要指定日期范围内的所有日期都显示出来,没有新增用户的日期返回0。

表结构

CREATE TABLE `user` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `username` varchar(255) CHARACTER SET utf8 DEFAULT NULL, 
  `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
  PRIMARY KEY (`id`), 
  UNIQUE KEY `username` (`username`) 
);

示例数据

INSERT INTO `user` VALUES 
(1,'user1','2018-01-02 10:01:01'),
(2,'user2','2018-01-02 10:11:01'),
(3,'user3','2018-01-03 10:01:01'),
(4,'user4','2018-01-03 10:11:01'),
(5,'user5','2018-01-03 10:21:01'),
(6,'user6','2018-01-03 10:41:01'),
(7,'user7','2018-01-05 10:01:01'),
(8,'user8','2018-01-05 10:11:01'),
(9,'user9','2018-01-05 10:21:01');

当前查询与结果

你现在使用的查询语句:

SELECT DATE_FORMAT(addtime, '%Y-%m-%d') AS Date, COUNT(id) AS total 
FROM user 
WHERE addtime BETWEEN '2018-01-01 00:00:00' AND '2018-01-07 00:00:00' 
GROUP BY YEAR(addtime), MONTH(addtime), DAY(addtime);

返回的结果只包含有注册用户的日期:

2018-01-02, 2
2018-01-03, 4
2018-01-05, 3

期望结果

希望得到指定范围内的所有日期,无新增用户的日期返回0:

2018-01-01, 0
2018-01-02, 2
2018-01-03, 4
2018-01-04, 0
2018-01-05, 3
2018-01-06, 0

解决方案

要实现这个需求,核心是先构建一个包含指定范围内所有连续日期的序列,再将这个序列和你的用户统计数据做左连接,这样空日期的统计值就会被填充为0。下面分两种MySQL版本给出方案:

方案1:MySQL 8.0及以上(支持递归CTE)

递归CTE是生成日期序列最简洁的方式,代码如下:

WITH RECURSIVE date_range AS (
    -- 定义起始日期
    SELECT '2018-01-01' AS date_val
    UNION ALL
    -- 递归生成后续日期,直到结束日期的前一天(匹配你的查询范围)
    SELECT DATE_ADD(date_val, INTERVAL 1 DAY)
    FROM date_range
    WHERE date_val < '2018-01-06'
)
SELECT 
    dr.date_val AS Date,
    -- 使用COALESCE将NULL替换为0
    COALESCE(u.total, 0) AS total
FROM date_range dr
LEFT JOIN (
    -- 原统计逻辑,按日期分组计算新增数
    SELECT DATE_FORMAT(addtime, '%Y-%m-%d') AS user_date, COUNT(id) AS total
    FROM user
    WHERE addtime BETWEEN '2018-01-01 00:00:00' AND '2018-01-07 00:00:00'
    GROUP BY user_date
) u ON dr.date_val = u.user_date
ORDER BY dr.date_val;

方案2:MySQL 5.x(不支持CTE)

如果你的MySQL版本较低,无法使用CTE,可以借助数字辅助表生成日期序列:

-- 创建临时数字表,这里生成0-6的数字,对应7天的日期范围
CREATE TEMPORARY TABLE nums (n INT);
INSERT INTO nums VALUES (0),(1),(2),(3),(4),(5),(6);

SELECT 
    DATE('2018-01-01') + INTERVAL n DAY AS Date,
    COALESCE(u.total, 0) AS total
FROM nums
LEFT JOIN (
    SELECT DATE_FORMAT(addtime, '%Y-%m-%d') AS user_date, COUNT(id) AS total
    FROM user
    WHERE addtime BETWEEN '2018-01-01 00:00:00' AND '2018-01-07 00:00:00'
    GROUP BY user_date
) u ON DATE('2018-01-01') + INTERVAL n DAY = u.user_date
-- 过滤出指定范围内的日期
WHERE DATE('2018-01-01') + INTERVAL n DAY <= '2018-01-06'
ORDER BY Date;

结果验证

以上两种方案都会返回你期望的结果:包含2018-01-01到2018-01-06的所有日期,没有新增用户的日期total字段显示为0。


内容的提问来源于stack exchange,提问作者rmh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:00:56