常见的统计解决方案

在这里插入图片描述

最近用MySQL做统计的需求比较多,这里整理一些常用的场景方便后期查阅,同时也是抛砖引玉的过程。其中包括普通的分组统计连续的每日统计区间范围统计

技术:MySQL, SpringDataJpa, Kotlin
说明:文章前半部分是场景分析,后半部分是语法分析
要点:GROUP BY, UNION, DATE_FORMAT, 流程控制函数

普通分组统计

场景一:根据订单状态统计订单数量。

一个很常见,也很简单的统计需求。其中状态字段是订单实体的一个属性。参考代码:(Kotlin语法)

@Query("SELECT status, COUNT(id) FROM Order GROUP BY status")
fun summaryOrderByStatus(): Array<Array<String>>?

场景二:根据订单中商品类目统计订单数量和金额。

比场景一稍微麻烦了一点,商品字段是订单实体的一个属性,而类目字段才是商品实体的一个属性。参考代码:(Kotlin语法)

@Query("SELECT commodity.category, COUNT(id), SUM(finalPrice) FROM Order GROUP BY commodity.category")
fun summaryOrderByCommodityCategory(): Array<Array<String>>?

小结:

一)、分组统计少不了GROUP BY语句,如果需要加查询条件,请在其前面添加 WHERE 语句。
二)、统计数量用COUNT,统计总和用SUM函数,有GROUP BY的地方,少不了这些聚合函数。
三)、统计返回的结果是字符串类型的二维数组。
四)、以内嵌属性分组,如果是SpringDataJpa框架,则可以直接通过"实体类.属性名"的方式。

每日统计

在做每日,每周,每月统计时,遇到返回日期不是连续的情况。原因是数据库中没有值,而我们理想状态应该是:如果没有值则默认为零,使其数据是连续的日期。

场景三:统计结果日期可能不连续

如果数据库中某个时间段没有值,那统计出来的结果会缺这段时间。参考代码:(sql语句)

-- 统计每日
SELECT DATE_FORMAT(create_date,'%Y-%m-%d') as days, COUNT(id) count FROM order GROUP BY days;
-- 统计每周
SELECT DATE_FORMAT(create_date,'%Y-%u') as weeks, COUNT(id) count FROM order GROUP BY weeks;
-- 统计每月
SELECT DATE_FORMAT(create_date,'%Y-%m') as months, COUNT(id) count FROM order GROUP BY months;

场景四:统计结果日期连续

要让日期连续,又要代码优雅。说实话,困扰了我很久,一直没有找到很好的解决方法,虽然目前这个方法很挫。但可以解决问题。毕竟抓到老鼠的都是好猫。如果各位有好的建议,望赐教!

解决思路:
第一步:创建一张date_summary辅助表,字段只需要有date和count(默认值为零)。
第二步:先向date_summary表插入10年内的数据。
第三步:通过UNION ALL 联合查询,将空缺的日期补上。

第二步参考代码(Kotlin语法)

val startDate = Calendar.getInstance()
startDate.set(2018, 6, 1)
val startTIme = startDate.timeInMillis
val endDate = Calendar.getInstance()
endDate.set(2028, 11, 30)
val endTime = endDate.timeInMillis
val oneDay = 1000 * 60 * 60 * 24L
var time = startTIme
val dates: MutableList<DateSummary> = arrayListOf()
while (time<=endTime) {
	val dateSummary = DateSummary()
	dateSummary.date = SimpleDateFormat("yyyy-MM-dd").format(Date(time))
	dateSummary.count = 0
	dates.add(dateSummary)
	time += oneDay
}
dateSummaryRepository.saveAll(dates)

第三步统计每日的SQL语句

SELECT
	summary.oneDay,
	summary.count 
FROM
	(
	SELECT
		DATE_FORMAT( created_date, '%Y-%m-%d' ) oneDay,
		COUNT(id) count 
	FROM
		service_order 
	WHERE created_date BETWEEN "2018-06-01" and "2018-08-01"
	GROUP BY oneDay 
	UNION ALL
		(
		SELECT
			DATE_FORMAT( date, '%Y-%m-%d' ) templateDay,
			count
		FROM
			date_summary
		WHERE date BETWEEN "2018-06-01" and "2018-08-01"
		GROUP BY
			templateDay
		) 
	) summary 
GROUP BY
	summary.oneDay 
ORDER BY
	summary.oneDay ASC

小结:

一)、MySQL的DATE_FORMAT(date,format) 函数用于以不同的格式显示日期/时间数据,文章后面会详细介绍
二)、MySQL的UNION 操作符用于合并两个或多个SELECT语句的结果集,文章后面会详细介绍

区间范围统计

这是一个较为常见的需求,比如按照年龄段统计人员分布情况,甚至要求分别统计男女人数分布情况。

场景五:根据小区年龄段统计人数

只根据年龄范围统计,没有其他限制条件,使用SUM只需要加一。

SELECT INTERVAL(age,10,20,30,40,50,60,70,80,90) AS ageRatio, SUM(1) AS count FROM user GROUP BY ageRatio

场景六:根据小区年龄段统计男女人数

在场景五的基础上多了一个区分性别,用流程控制函数来设置SUM加一的情况。

SELECT INTERVAL(age,10,20,30,40,50,60,70,80,90) AS ageRatio, 
SUM(CASE WHEN sex=1 THEN 1 ELSE 0 END) AS male,
SUM(CASE WHEN sex=0 THEN 1 ELSE 0 END) AS female FROM user GROUP BY ageRatio

小结:

一)、通过区间统计需要使用MySQL的INTERVAL函数,第一个参数是需要比较的字段,后面是比较的区间,值必须从小到大
二)、区间统计的结果也是二维数组,注意返回的结果可能不是连续的(这里的不连续可以用代码解决,毕竟区间数量较少)。第一个参数返回的是区间的下标,从0开始。
三)、当age的值在区间范围内就SUM加一,也可以通过流程控制函数(CASE WHEN THEN ELSE END)来判断是加一还是加零

MySQL知识点

知道现在都是快餐文化,大家都很忙,很少有时间去揣摩各语法的特点。所以先把常用的场景写在前面,语法知识写在后面。

GROUP BY 分组

一)、分组一般与聚合函数一起使用如SUM,COUNT等
二)、GROUP BY 在WHERE 语句之后

DATE_FORMAT 时间格式化

一)、用来修改时间的格式
二)、语法格式: DATE_FORMAT(date,format) date必须是合格的时间参数,format是输出时间格式
三)、常见的format格式有:

  • %Y: 4位数的年,
  • %y: 2位数的年,
  • %m: 2位数的月(00~12),
  • %M: 英文单词的月,
  • %d: 2位数的日(00~31),
  • %u: 周,星期一是一周的第一条,
  • 更多可以访问w3school

UNION 联合结果

一)、UNION可以合并、联合,将多次查询结果合并成一个结果,通过查询结果合并解决了统计不连续的情况。
二)、多条查询语句的列数必须一致,各列的顺序最好一致。场景四中,两条sql都只查询了date和count,且顺序保持一致。
三)、union 去重,union all包含重复项

INTERVAL 比较间距

一)、INTERVAL()函数是比较列表(N, arg1, arg2, arg3…argN)中的N值。
二)、INTERVAL()函数如果N<arg1则返回0,如果N<arg2则返回1,如果N<arg3则返回2,如果N为NULL,它将返回-1。
三)、列表值必须是arg1 < arg2 < arg3 的形式才能正常工作。

流程控制函数

一)、case when then else end 是流程控制函数中的一种,还有一种是if函数
二)、使用语法:

case 
when 条件1 then1
when 条件2 then2
...
else 值n
end

文章到这里就结束了。如果文章对你有帮助,可以点个"推荐",也可以"关注"我,获得更多丰富的知识。若文中有什么不对或者不严谨的地方,请指正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、workbook,一个可以记录、管理、查询、统计工作日志的小工具。 2、运行在命令行模式下,不用鼠标即可完成全部操作。 3、可以记录每天的工作内容,并对工作内容可以进行增删改操作。 4、可以对工作内容进行查询和统计,比如在某一段时间内,你都做了哪些工作?这些工作各占用了你多少时间?该工作在你的工作时间内占用了多大的比例? 等等。 5、工作内容包括:工作类别、工作开始日期、工作结束日期、工作时长、工作内容 6、对每个工作内容强制进行分类,分类的类别完全自定义 7、对每个工作内容,需要提供该工作共花费了你多少时间,也就是工作时长;该时长不要求是非常精确,你可以给出一个大约值,当然,越精确越好。 也可以不提供时长,但是如果没有提供时长,则被认为该工作是没有完成的。你可以在工作还没有完成时记录一下日志,然后再完成以后记录一下时长。 8、工作的状态分为完成和未完成,完成的工作会记录完成时的日期。 9、提供登录密码功能来保护隐私安全,可以修改密码,可以初始化密码,初始密码为:123456,请及时修改密码。 10、该软件使用JAVA语言编写,数据库使用的是H2。数据文件的名称为workbookdb.h2.db,该文件记录了所有的工作日志,所以请及时备份该文件。 11、该工具不需要安装,所有文件都必须放在同一个目录下才能运行。 12、由于本工具使用JAVA语言编写,请把JRE整个文件夹拷贝到该工具的同一个目录下,再运行本工具。 13、本工具分为2个版本:windows版本、Linux版本。windows版本请运行workbook.bat;Linux版本请运行workbook.sh,如果没有权限,请赋权后执行。 14、如果有问题,欢迎在作者的博客中留言交流:http://blog.csdn.net/dbsync/article/details/11267233 运行方法:首先拷贝JRE整个目录,放到本工具的目录下,然后windows上运行workbook.bat;linux上运行workbook.sh 初始密码:123456 作者:滴石水
1、workbook,一个可以记录、管理、查询、统计工作日志的小工具。 2、运行在命令行模式下,不用鼠标即可完成全部操作。 3、可以记录每天的工作内容,并对工作内容可以进行增删改操作。 4、可以对工作内容进行查询和统计,比如在某一段时间内,你都做了哪些工作?这些工作各占用了你多少时间?该工作在你的工作时间内占用了多大的比例? 等等。 5、工作内容包括:工作类别、工作开始日期、工作结束日期、工作时长、工作内容 6、对每个工作内容强制进行分类,分类的类别完全自定义 7、对每个工作内容,需要提供该工作共花费了你多少时间,也就是工作时长;该时长不要求是非常精确,你可以给出一个大约值,当然,越精确越好。 也可以不提供时长,但是如果没有提供时长,则被认为该工作是没有完成的。你可以在工作还没有完成时记录一下日志,然后再完成以后记录一下时长。 8、工作的状态分为完成和未完成,完成的工作会记录完成时的日期。 9、提供登录密码功能来保护隐私安全,可以修改密码,可以初始化密码,初始密码为:123456,请及时修改密码。 10、该软件使用JAVA语言编写,数据库使用的是H2。数据文件的名称为workbookdb.h2.db,该文件记录了所有的工作日志,所以请及时备份该文件。 11、该工具不需要安装,所有文件都必须放在同一个目录下才能运行。 12、由于本工具使用JAVA语言编写,请把JRE整个文件夹拷贝到该工具的同一个目录下,再运行本工具。 13、本工具分为2个版本:windows版本、Linux版本。windows版本请运行workbook.bat;Linux版本请运行workbook.sh,如果没有权限,请赋权后执行。 14、如果有问题,欢迎在作者的博客中留言交流:http://blog.csdn.net/dbsync/article/details/11267233 运行方法:首先拷贝JRE整个目录,放到本工具的目录下,然后windows上运行workbook.bat;linux上运行workbook.sh 初始密码:123456 作者:滴石水
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值