侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

mysql查询每小时数据和上小时数据的差值实现思路详解

数据库  /  管理员 发布于 6年前   491

一、前言

      需求是获取某个时间范围内每小时数据和上小时数据的差值以及比率。本来以为会是一个很简单的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 difffrom (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 difffrom (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 |+------+

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

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

本小时 上个小时  差值
15442 15114  -328
15230 15442  212
14654 15230  576
14933 14654  -279
14768 14933  165

      可以看到确实是成功获取到了差值。如果要获取差值的比率的话,直接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.1when days = days1 and (nums1 - nums)/nums1 > 0.1 and (nums1 - nums)/nums1 < 0.2 then 0.2when days = days1 and (nums1 - nums)/nums1 > 0.2 and (nums1 - nums)/nums1 < 0.3 then 0.3when days = days1 and (nums1 - nums)/nums1 > 0.3 and (nums1 - nums)/nums1 < 0.4 then 0.4when days = days1 and (nums1 - nums)/nums1 > 0.4 and (nums1 - nums)/nums1 < 0.5 then 0.5when days = days1 and (nums1 - nums)/nums1 > 0.5 then 0.6 else 0 end as diff,count(*) as diff_numsfrom (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同学有时候也不靠谱,还是要靠自己啊

补充介绍:MySQL数据库时间和实际时间差8个小时

url=jdbc:mysql://127.0.0.1:3306/somedatabase?characterEncoding=utf-8&serverTimezone=GMT%2B8

数据库配置后面加上&serverTimezone=GMT%2B8

到此这篇关于mysql查询每小时数据和上小时数据的差值的文章就介绍到这了,更多相关mysql 每小时数据差值内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


  • 上一条:
    MySQL必备的常见知识点汇总整理
    下一条:
    mysql条件查询and or使用方法及优先级实例分析
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客