一、前言

需求是获取某个时间范围内每小时数据和上小时数据的差值以及比率。本来以为会是一个很简单的 sql ,结果思考两分钟发现并不简单,网上也没找到参考的方案,那就只能自己慢慢分析了。

刚开始没思路,就去问 DBA 同学,结果 DBA 说他不会,让我写 php 脚本去计算,,这就有点过分了,我只是想临时查个数据,就不信直接用 sql 查不出来,行叭,咱们边走边试。

博主这里用的是笨方法实现的,各位大佬要是有更简单的方式,请不吝赐教,评论区等你!

mysql版本:

mysql> select version();

+---------------------+

| version() |

+---------------------+

| 10.0.22-MariaDB-log |

+---------------------+

1 row in set (0.00 sec)

二、查询每个小时和上小时的差值

1、拆分需求

这里先分开查询下,看看数据都是多少,方便后续的组合。

(1)获取每小时的数据量

这里为了方便展示,直接合并了下,只显示 01-12 时的数据,并不是 bug 。。

select count(*) as nums,date_format(log_time,'%Y-%m-%d %h') as days from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days;

+-------+---------------+

| nums | days |

+-------+---------------+

| 15442 | 2020-04-19 01 |

| 15230 | 2020-04-19 02 |

| 14654 | 2020-04-19 03 |

| 14933 | 2020-04-19 04 |

| 14768 | 2020-04-19 05 |

| 15390 | 2020-04-19 06 |

| 15611 | 2020-04-19 07 |

| 15659 | 2020-04-19 08 |

| 15398 | 2020-04-19 09 |

| 15207 | 2020-04-19 10 |

| 14860 | 2020-04-19 11 |

| 15114 | 2020-04-19 12 |

+-------+---------------+

(2)获取上小时的数据量

select count(*) as nums1,date_format(date_sub(date_format(log_time,'%Y-%m-%d %h'),interval -1 hour),'%Y-%m-%d %h') as days from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days;

+-------+---------------+

| nums1 | days |

+-------+---------------+

| 15114 | 2020-04-19 01 |

| 15442 | 2020-04-19 02 |

| 15230 | 2020-04-19 03 |

| 14654 | 2020-04-19 04 |

| 14933 | 2020-04-19 05 |

| 14768 | 2020-04-19 06 |

| 15390 | 2020-04-19 07 |

| 15611 | 2020-04-19 08 |

| 15659 | 2020-04-19 09 |

| 15398 | 2020-04-19 10 |

| 15207 | 2020-04-19 11 |

| 14860 | 2020-04-19 12 |

+-------+---------------+

注意:

1)获取上小时数据用的是date_sub()函数,date_sub(日期,interval -1 hour)代表获取日期参数的上个小时,具体参考手册:https://www.w3school.com.cn/sql/func_date_sub.asp

2)这里最外层嵌套了个date_format是为了保持格式和上面的一致,如果不加这个date_format的话,查询出来的日期格式是:2020-04-19 04:00:00的,不方便对比。

2、把这两份数据放到一起看看

select nums ,nums1,days,days1

from

(select count(*) as nums,date_format(log_time,'%Y-%m-%d %h') as days from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days) as m,

(select count(*) as nums1,date_format(date_sub(date_format(log_time,'%Y-%m-%d %h'),interval -1 hour),'%Y-%m-%d %h') as days1 from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days1) as n;

+-------+-------+---------------+---------------+

| nums | nums1 | days | days1 |

+-------+-------+---------------+---------------+

| 15442 | 15114 | 2020-04-19 01 | 2020-04-19 01 |

| 15442 | 15442 | 2020-04-19 01 | 2020-04-19 02 |

| 15442 | 15230 | 2020-04-19 01 | 2020-04-19 03 |

| 15442 | 14654 | 2020-04-19 01 | 2020-04-19 04 |

| 15442 | 14933 | 2020-04-19 01 | 2020-04-19 05 |

| 15442 | 14768 | 2020-04-19 01 | 2020-04-19 06 |

| 15442 | 15390 | 2020-04-19 01 | 2020-04-19 07 |

| 15442 | 15611 | 2020-04-19 01 | 2020-04-19 08 |

| 15442 | 15659 | 2020-04-19 01 | 2020-04-19 09 |

| 15442 | 15398 | 2020-04-19 01 | 2020-04-19 10 |

| 15442 | 15207 | 2020-04-19 01 | 2020-04-19 11 |

| 15442 | 14860 | 2020-04-19 01 | 2020-04-19 12 |

| 15230 | 15114 | 2020-04-19 02 | 2020-04-19 01 |

| 15230 | 15442 | 2020-04-19 02 | 2020-04-19 02 |

| 15230 | 15230 | 2020-04-19 02 | 2020-04-19 03 |

可以看到这样组合到一起是类似于程序中的嵌套循环效果,相当于 nums 是外层循环, nums1 是内存循环。循环的时候先用 nums 的值,匹配所有 nums1 的值。类似于 php 程序中的:

foreach($arr as $k=>$v){

foreach($arr1 as $k1=>$v1){

}

}

既然如此,那我们是否可以像平时写程序的那样,找到两个循环数组的相同值,然后进行求差值呢?很明显这里的日期是完全一致的,可以作为对比的条件。

3、使用case …when 计算差值

select (case when days = days1 then (nums - nums1) else 0 end) as diff

from

(select count(*) as nums,date_format(log_time,'%Y-%m-%d %h') as days from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days) as m,

(select count(*) as nums1,date_format(date_sub(date_format(log_time,'%Y-%m-%d %h'),interval -1 hour),'%Y-%m-%d %h') as days1 from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days1) as n;

效果:

+------+

| diff |

+------+

| 328 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| -212 |

| 0 |

| 0

可以看到这里使用 case..when 实现了当两个日期相等的时候,就计算差值,近似于 php 程序的:

foreach($arr as $k=>$v){

foreach($arr1 as $k1=>$v1){

if($k == $k1){

//求差值

}

}

}

结果看到有大量的 0 ,也有一部分计算出的结果,不过如果排除掉这些0的话,看起来好像有戏的。

4、过滤掉结果为0 的部分,对比最终数据

这里用 having 来对查询的结果进行过滤。 having 子句可以让我们筛选成组后的各组数据,虽然我们的 sql 在最后面没有进行 group by ,不过两个子查询里面都有 group by 了,理论上来讲用 having 来筛选数据是再合适不过了,试一试

select (case when days = days1 then (nums1 - nums) else 0 end) as diff

from

(select count(*) as nums,date_format(log_time,'%Y-%m-%d %h') as days from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days) as m,

(select count(*) as nums1,date_format(date_sub(date_format(log_time,'%Y-%m-%d %h'),interval -1 hour),'%Y-%m-%d %h') as days1 from test where 1 and log_time >='2020-04-19 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days1) as n having diff <>0;

结果:

+------+

| diff |

+------+

| -328 |

| 212 |

| 576 |

| -279 |

| 165 |

| -622 |

| -221 |

| -48 |

| 261 |

| 191 |

| 347 |

| -254 |

+------+

这里看到计算出了结果,那大概对比下吧,下面是手动列出来的部分数据:

当前小时和上个小时的差值: 当前小时 -上个小时

本小时上个小时差值

1544215114-328

1523015442212

1465415230576

1493314654-279

1476814933165

可以看到确实是成功获取到了差值。如果要获取差值的比率的话,直接 case when days = days1 then (nums1 - nums)/nums1 else 0 end 即可。

5、获取本小时和上小时数据的降幅,并展示各个降幅范围的个数

在原来的 case..when 的基础上引申一下,继续增加条件划分范围,并且最后再按照降幅范围进行 group by 求和即可。这个 sql 比较麻烦点,大家有需要的话可以按需修改下,实际测试是可以用的。

select case

when days = days1 and (nums1 - nums)/nums1 < 0.1 then 0.1

when days = days1 and (nums1 - nums)/nums1 > 0.1 and (nums1 - nums)/nums1 < 0.2 then 0.2

when days = days1 and (nums1 - nums)/nums1 > 0.2 and (nums1 - nums)/nums1 < 0.3 then 0.3

when days = days1 and (nums1 - nums)/nums1 > 0.3 and (nums1 - nums)/nums1 < 0.4 then 0.4

when days = days1 and (nums1 - nums)/nums1 > 0.4 and (nums1 - nums)/nums1 < 0.5 then 0.5

when days = days1 and (nums1 - nums)/nums1 > 0.5 then 0.6

else 0 end as diff,count(*) as diff_nums

from

(select count(*) as nums,date_format(log_time,'%Y-%m-%d %h') as days from test where 1 and log_time >='2020-03-20 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days) as m,

(select count(*) as nums1,date_format(date_sub(date_format(log_time,'%Y-%m-%d %h'),interval -1 hour),'%Y-%m-%d %h') as days1 from test where 1 and log_time >='2020-03-20 00:00:00' and log_time <= '2020-04-20 00:00:00' group by days1) as n group by diff having diff >0;

结果:

+------+-----------+

| diff | diff_nums |

+------+-----------+

| 0.1 | 360 |

| 0.2 | 10 |

| 0.3 | 1 |

| 0.4 | 1 |

+------+-----------+

三、总结

1、 sql 其实和程序代码差不多,拆分需求一步步组合,大部分需求都是可以实现的。一开始就怂了,那自然是写不出的。

2、 不过复杂的计算,一般是不建议用 sql 来写,用程序写会更快, sql 越复杂,效率就会越低。

3、 DBA 同学有时候也不靠谱,还是要靠自己啊

end

每小时的数据mysql_荐 mysql查询每小时数据和上小时数据的差值相关推荐

  1. mysql 查询案例dept,emp表内数据

    mysql 查询案例dept,emp表内数据 部门表 员工表 工资等级表 查询案例: 部门表 CREATE TABLE DEPT( DEPTNO INT PRIMARY KEY, – 部门编号 DNA ...

  2. MYSQL查询大于创建时间一小时的数据

    以下代码中times为时间字段,类型为datetime 1.查询大于times一小时的数据 //大于号后面都是获取times一小时后的时间 select*from table where now() ...

  3. php如何查询本周的数据,php、mysql查询当天,查询本周,查询本月的数据实例

    //其中 video 是表名: //createtime 是字段: // //数据库time字段为时间戳 // //查询当天: $start = date('Y-m-d 00:00:00'); $en ...

  4. mysql查询前12个月的数据_MySQL 统计过去12个月的数据(包括本月),mysql本月

    MySQL 统计过去12个月的数据(包括本月),mysql本月 1.问题 需要统计过去12个月的数据,如现在是2015年4月,那么我们需要统计从2014年5月到2015年4月的数据情况.而这12个月中 ...

  5. mysql查询所有分类前三的数据

    设计思路 当mysql查询有很多分类时,可能只需要每种分类的前三或者前十的数据,不需要返回所有的结果,所以我们可以给不同种类的数据添加序号,然后通过序号来筛选结果 例:建一张工人工作质量表,用年份和质 ...

  6. mysql 查询最接近某个时间段的数据

    查询最接近某个 小时的数据 SELECT * FROM 表名 WHERE hour(时间字段) BETWEEN 8 and 12 and 时间字段 BETWEEN '2022-10-01' and N ...

  7. mysql查询转json数据库_json格式数据,将数据库中查询的结果转换为json, 然后调用接口的方式返回json(方式一)...

    调用接口,无非也就是打开链接 读取流 将结果以流的形式输出 将查询结果以json返回,无非就是将查询到的结果转换成jsonObject ================================ ...

  8. mysql本周数据没有填充_MySql查询本周、本月、本年数据(没有数据则补全0)

    最近写项目,发现有很多图表统计,需要查询本周.本月.本年数据.但是图表需要两个数组,一个日期数组,一个数据数组.然而数据库查询却只能查询出有数据的日期数据,所以找了很多资料终于能有补全日期和数据的方法 ...

  9. mysql查询最小的id_Mysql查询表中最小可用id值的方法

    今天在看实验室的项目时,碰到了一个让我"棘手"的问题,其实也是自己太笨了.先把 sql 语句扔出来 // 这条语句在id没有1时,不能得到正确的查询结果. select min(i ...

最新文章

  1. oracle带时间查询语句,请教oracle按时间分组查询语句的写法
  2. 开源,不是一种道德绑架
  3. Cisco小型局域网配置实验
  4. stm32 串口通信数据移位寄存器_STM32串口接RS485丢码问题已解决*_*
  5. vue监听数组元素属性的变化_为什么Vue3.0不再使用defineProperty实现数据监听?
  6. k近邻算法_机器学习算法之——K最近邻(k-Nearest Neighbor,KNN)分类算法原理讲解...
  7. php云erp进销存v8手机端,PHP仿金蝶云ERP进销存V8网络多仓版源码
  8. 西安理工大学计算机科学与技术分数线,2017西安理工大学各专业录取分数线
  9. 【老生谈算法】matlab实现方位角计算源码——方位角计算
  10. blast2go windows 下本地化
  11. java String 转map、list
  12. 新氧科技CEO金星直播背后:助推产业线上化,打造医美“新基建”
  13. UVa 11909 - Soya Milk
  14. OpenCV-细化算法(thinning algorithm)描绘出轮廓的中心线
  15. 支付宝网商贷是雪中送炭么?
  16. DataStream API【1】
  17. R数据分析:跟随top期刊手把手教你做一个临床预测模型
  18. catia 螺钉外螺纹_请问catia如何画螺杆和螺栓上的螺纹
  19. 1、新建基于标准固件库MDK5工程模板(STM32F103ZET6)
  20. https协议能否让网站,优先被百度收录,个人观点

热门文章

  1. 第三次学JAVA再学不好就吃翔(part91)--Map接口
  2. python观察日志(part22)--设置工作目录及文件读取
  3. 第三次学JAVA再学不好就吃翔(part36)--抽象类
  4. python的盈利模式_八大盈利模式是什么?一篇文教会你盈利模式分析!
  5. 有的时候不评价别人其实挺难的
  6. 如何在源代码(而非库文件)模式下构建并且运行 SAP Spartacus
  7. 如何判断当前的SAP Spartacus已经运行在SSR模式,而不是PWA模式下了
  8. SAP Spartacus payment detail page的CMS模型
  9. SAP Spartacus BrowserPlatformLocation的初始化逻辑
  10. Filter handling in SAP gateway