MySQL统计近7天、近6个月、近3年的记录,没有记0

2 篇文章 0 订阅

测试数据表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for test
-- ----------------------------
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `datetime` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES (1, '小A', '2021-07-09 11:39:38');
INSERT INTO `test` VALUES (2, '小B', '2021-07-08 11:40:03');
INSERT INTO `test` VALUES (3, '小C', '2021-07-07 11:40:21');
INSERT INTO `test` VALUES (4, '小D', '2021-07-06 11:40:22');
INSERT INTO `test` VALUES (5, '小E', '2021-07-05 11:40:23');
INSERT INTO `test` VALUES (6, '小F', '2021-07-04 11:40:24');
INSERT INTO `test` VALUES (7, '小G', '2021-07-03 11:40:25');
INSERT INTO `test` VALUES (8, '中F', '2021-06-21 11:42:09');
INSERT INTO `test` VALUES (9, '中H', '2021-05-25 11:42:46');
INSERT INTO `test` VALUES (10, '大I', '2020-06-09 11:43:36');
INSERT INTO `test` VALUES (11, '大J', '2019-04-29 11:43:55');

SET FOREIGN_KEY_CHECKS = 1;

说明 

实际上,我们无论是统计近7天、近6个月、近3年的数据,原理都是一样。都需要构建一个日期的结果集,然后去 left join 需要统计的表,然后通过 group bycount 来分类汇总。

这里先说一种错误的做法,即直接根据日期,通过 left 截取出给定的日期精度来 group by,然后 count 统计汇总。示例SQL如下。

 如上图结果所示,7月10号没有数据,所以结果集中就没有该日期的数据。这显然不符合我们的要求,我们的要求是,如果没有数据,那么当天应该显示0。这也就是问题所在。

当然,如果你能确保给定的日期精度下都必然有数据,那么这种做法的结果和下面所讲的方法的结果是一样,甚至效率要比下面讲的方法要高很多,以至于我推荐你用这种方法即可

统计近七天的数据

1、构建一个日期的结果集

SELECT CURDATE() AS datetime
union all
SELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY) AS datetime
union all
SELECT DATE_SUB(CURDATE(), INTERVAL 2 DAY) AS datetime
union all
SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY) AS datetime
union all
SELECT DATE_SUB(CURDATE(), INTERVAL 4 DAY) AS datetime
union all
SELECT DATE_SUB(CURDATE(), INTERVAL 5 DAY) AS datetime
union all
SELECT DATE_SUB(CURDATE(), INTERVAL 6 DAY) AS datetime

2、汇总数据表近7次数据(允许部分日期没有数据,没有则跳过,确保有7条数据即可) 

SELECT LEFT(datetime, 10) AS datetime, COUNT(1) AS num 
FROM test GROUP BY LEFT(datetime, 10) ORDER BY datetime DESC LIMIT 7

3、结果集左连接数据表汇总数据(完成)

SELECT t1.datetime, IFNULL(t2.num, 0) AS num FROM (
	SELECT CURDATE() AS datetime
	union all
	SELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY) AS datetime
	union all
	SELECT DATE_SUB(CURDATE(), INTERVAL 2 DAY) AS datetime
	union all
	SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY) AS datetime
	union all
	SELECT DATE_SUB(CURDATE(), INTERVAL 4 DAY) AS datetime
	union all
	SELECT DATE_SUB(CURDATE(), INTERVAL 5 DAY) AS datetime
	union all
	SELECT DATE_SUB(CURDATE(), INTERVAL 6 DAY) AS datetime
) t1 LEFT JOIN (
	SELECT LEFT(datetime, 10) AS datetime, COUNT(1) AS num 
	FROM test GROUP BY LEFT(datetime, 10) ORDER BY datetime DESC LIMIT 7
) t2 ON t1.datetime = t2.datetime ORDER BY t1.datetime DESC

如上,正确的做法分三部分,对于不同的日期精度,我们只需修改部分参数即可。下面直接给出结果,不再分步说明。

统计近6个月的数据

SELECT t1.datetime, IFNULL(t2.num, 0) AS num FROM (
    SELECT DATE_FORMAT(CURDATE(), '%Y-%m') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 1 MONTH), '%Y-%m') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 2 MONTH), '%Y-%m') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 3 MONTH), '%Y-%m') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 4 MONTH), '%Y-%m') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 5 MONTH), '%Y-%m') AS datetime
) t1 LEFT JOIN (
	SELECT LEFT(datetime, 7) AS datetime, COUNT(1) AS num 
	FROM test GROUP BY LEFT(datetime, 7) ORDER BY datetime DESC LIMIT 6
) t2 ON t1.datetime = t2.datetime ORDER BY t1.datetime DESC

统计近3年的数据

SELECT t1.datetime, IFNULL(t2.num, 0) AS num FROM (
	SELECT DATE_FORMAT(CURDATE(), '%Y') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 1 YEAR), '%Y') AS datetime
	union all
	SELECT DATE_FORMAT((CURDATE() - INTERVAL 2 YEAR), '%Y') AS datetime
) t1 LEFT JOIN (
	SELECT LEFT(datetime, 4) AS datetime, COUNT(1) AS num 
	FROM test GROUP BY LEFT(datetime, 4) ORDER BY datetime DESC LIMIT 3
) t2 ON t1.datetime = t2.datetime ORDER BY t1.datetime DESC
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值