上周被任命一个统计接口的实现。
其实单纯的统计查询很简单的,分组加聚合函数一般就能搞定了,但是问题是补0问题。
正常的统计查询:
单纯的统计查询
但是这个放在需求上大多数时候都是满足不了的!因为一般这种统计前端都是图表展示,你就这么孤零零的两条数据,不想打架的话还是得老老实实处理一下的。
这个处理分两种:
-
代码中遍历循环,我同事就采用了这种方法。据说是采用1-31遍历循环的,不过我手里没有源码,所以不确定具体的实现方法,反正听说是一个月固定31天,比如2月,2,4,9,11之类的,也是31天,不知道最后展现 的结果前台怎么实现的。
但是我虽然没用代码实现过,但是猜测应该是可以解决这个月份的天数问题吧?不过又要判断年,又要判断月,实现是可以实现,估计也挺麻烦、注意是麻烦不是困难,一层层判断呗。 - 这个也是我实现的方法:日历类。
在数据库中添加一个日历表,用来使每一天都有记录,当天没数据则count是0。这个也就是上文中说的补0.
可能听起来这个比较麻烦,改动还大,毕竟要添加一张表,但是其实没想的那么复杂,毕竟现在网络上这种轮子都有(往下的操作好多是看帖子学的,不过因为是上周实现,很多代码不知道出处了,所以不注明来自于)。而且好多时候我们统计的不仅仅是一种数据,可能涉及到好多种,比如司机啊,注册用户量啊,订单量啊之类之类的,而一个日历类可以应用于所有的统计,甚至包括年月日的统计,真的,我非常推荐这种日历表的方法。
日历表的实现
-
创建日历表脚本
首先,日历表的创建和数据的插入如果自己手写,确实麻烦的不行,但是刚刚说的前人的轮子也不是吃素的,如下脚本:
CREATE TABLE num (i int);-- 创建一个表用来储存0-9的数字
INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);-- 生成0-9的数字,方便以后计算时间
CREATE TABLE if not exists calendar(datelist date); -- 生成一个存储日期的表,datalist是字段名
-- 这里是生成并插入日期数据
INSERT INTO calendar(datelist) SELECT
adddate(
( -- 这里的起始日期,你可以换成当前日期
DATE_FORMAT("2018-1-1", '%Y-%m-%d')
),
numlist.id
) AS `date`
FROM
(
SELECT
n1.i + n10.i * 10 + n100.i * 100 + n1000.i * 1000+ n10000.i * 10000 AS id
FROM
num n1
CROSS JOIN num AS n10
CROSS JOIN num AS n100
CROSS JOIN num AS n1000
CROSS JOIN num AS n10000
) AS numlist;
直接复制粘贴,然后运行就ok了!因为我用的Navicat,所以更是方便的不行:
运行结果
运行完成后,我们刷新下列表:
如上所示
日历表就是我们所需要用的表,而num这个表是工具表,此时可以删除了。这时我们打开这个calendar表:
calendar表数据
从2018年开始,到2291年结束。二百多年的日历,别说用到辞职了,用到我死都绰绰有余。而且还可以酌情删除一部分数据,比如我是19年10月开发的,在之前的 数据不会统计,所以还可以删除2019-09包括之前的数据,至于往后截取时间,看你心情咯。
-
使用这个日历表查询
其实这个日历表就是为了查询补0的,所以在查询的时候要关联查询
其实之前我做的时候都一路顺风,但是这一步却卡了一会儿, 最后还是在我一个好友的帮助下完成的,在此感谢我好友一波。同时深感sql功底薄弱,面壁三秒。
在这我把sql语句贴出来供大家参考:
按日期统计:
SELECT
c.datelist as date,
COUNT(b.id) as count
FROM
calendar AS c
LEFT JOIN (
SELECT
*
FROM
driver -- 真正想统计的表名
WHERE
lnvalid = 2 -- 这个是查询条件,你们酌情写自己的
AND flag = 0 -- 这个是查询条件,你们酌情写自己的
) AS b ON c.datelist = DATE(b.create_time) -- 两个表的关联,因为我表中crate_time是年月日时分秒的,所以要格式化后相等
WHERE
c.datelist LIKE '2019-10%' -- 这个是查询某月的日期统计,在代码中这块应该是一个参数。我这里查询的2019年10月份的统计
GROUP BY
datelist -- 这个分组按照日期分组,再次声明这个是天的,如果月的这里会不同
ORDER BY
datelist -- 这个排序是因为之前一次测试有count的在上面,没有的在下面,日期没有顺序,所以我又升序排了下。
我一如既往的风格,注解墨迹的不行,大家对付看吧,毕竟总比没注释让人摸不着头脑强。
按月份统计:
SELECT
DATE_FORMAT(c.datelist, '%Y-%m') as date, -- 查询的是年-月,所以要格式处理
COUNT(b.id) as count
FROM
calendar AS c
LEFT JOIN (
SELECT
*
FROM
driver -- 真正想统计的表名
WHERE
lnvalid = 2 -- 这个是查询条件,你们酌情写自己的
AND flag = 0 -- 这个是查询条件,你们酌情写自己的
) AS b ON c.datelist = DATE(b.create_time) -- 两个表的关联,因为我表中crate_time是年月日时分秒的,所以要格式化后相等
WHERE
c.datelist LIKE '2019%' -- 这个是查询某月的日期统计,在代码中这块应该是一个参数。我这里查询的2019年的统计
GROUP BY
DATE_FORMAT(c.datelist, '%Y-%m')-- 这个分组按照月份分组的,因为datelist是年月日,所以要格式化处理成年月
ORDER BY
datelist -- 这个排序是因为之前一次测试有count的在上面,没有的在下面,日期没有顺序,所以我又升序排了下。
按照年统计:
SELECT
DATE_FORMAT(c.datelist, '%Y') as date, -- 查询的是年,所以要格式处理
COUNT(b.id) as count
FROM
calendar AS c
LEFT JOIN (
SELECT
*
FROM
base_driver -- 真正想统计的表名
WHERE
if_lnvalid = 2 -- 这个是查询条件,你们酌情写自己的
AND flag = 0 -- 这个是查询条件,你们酌情写自己的
) AS b ON c.datelist = DATE(b.create_time) -- 两个表的关联,因为我表中crate_time是年月日时分秒的,所以要格式化后相等
GROUP BY
DATE_FORMAT(c.datelist, '%Y')-- 这个分组按照月份分组的,因为datelist是年月日,所以要格式化处理成年
ORDER BY
datelist -- 这个排序是因为之前一次测试有count的在上面,没有的在下面,日期没有顺序,所以我又升序排了下。
至此,三个常用的统计查询完成。因为我是多个统计,所以剩下的就是将不同的表与此日历表联合查询啦。
此文仅讲mysql中补0的实现,下一篇讲java代码的实现步骤。
我有一个梦想,若干年后,不管遇到什么问题,翻翻自己的简书,在上面都能找到答案,哈哈,做梦都要笑醒了。所以哪怕为了实现这个梦想,我也愿意事无大小,学到了就记录起来。毕竟我相信文字不会骗人,若干年后,再遇到这样的问题,记忆可能会淡忘,但是我记录的文章是实实在在的啊~
全文手打不易,如果稍微帮到你了,请点个喜欢点个关注支持一下~~~~~也祝大家工作顺顺利利!