酷站(www.ku0.com)-致力于为互联网从业者提供动力!

热门关键词:  企业  as  baidu  c4rp3nt3r  美女
【ECS精选特惠】新用户上云低至1折起
百度资源

mysql查询每小时数据和上小时数据的差值的实现方法

来源:互联网搜集 作者:秩名 人气: 发布时间:2020-04-25
本篇文章主要介绍了mysql查询每小时数据和上小时数据的差值的实现方法,对大家的学习或者工作具有一定的参考学习价值,感兴趣的小伙伴们可以参考一下,也感谢大家对酷站(ku0.com)的支持。

一、前言

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

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

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

本小时 上个小时  差值
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.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同学有时候也不靠谱,还是要靠自己啊

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

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

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

版权声明:本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 959677720#qq.cn(#换@) 举报,一经查实,本站将立刻删除。
原文链接:https://blog.csdn.net/LJFPHP/article/details/105659791

相关文章

  • MySQL explain获取查询指令信息原理介绍

    MySQL explain获取查询指令信息原理介绍

    explain用于获取查询执行计划信息, 一、语法 只需要在select前加上explain即可,如: mysql explain select 1;+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------......
    05-15
  • mysql查询每小时数据和上小时数据的差值的实现方法

    mysql查询每小时数据和上小时数据的差值的实现方法

    一、前言 需求是获取某个时间范围内每小时数据和上小时数据的差值以及比率。本来以为会是一个很简单的 sql ,结果思考两分钟发现并不简单,网上也没找到参考的方案,那就只能自己慢慢分析了。 刚开始没思路,就去问 DBA 同学,结果 DBA ......
    04-25
  • mysql条件查询and or使用方法及优先级

    mysql条件查询and or使用方法及优先级

    mysql and与or介绍 AND 和 OR 可在 WHERE 子语句中把两个或多个条件结合起来。 使用OR关键字时: 只要符合这几个查询条件的其中一个条件,这样的记录就会被查询出来。 如果不符合这些查询条件中的任何一条,这样的记录将被排除掉。 使用a......
    04-23
  • MySQL表中非主键列溢出情况监控的介绍

    MySQL表中非主键列溢出情况监控的介绍

    这次遇到的坑,更加的隐蔽。 是一个log表里面的一个int signed类型的列写满了。快速的解决方法当然还是只能切新表来救急了,然后搬迁老表的部分历史数据到热表。 亡羊补牢,处理完故障后,赶紧写脚本把生产的其他表都捋一遍。 下面是我暂......
    04-20
  • MySQL表自增id溢出的故障复盘解决的方法

    MySQL表自增id溢出的故障复盘解决的方法

    问题:MySQL某个表自增id溢出导致某业务block 背景: tokudb引擎的一个大表tb1,存放业务上的机审日志,每天有大量的写入, 并且由于历史原因,这张表是int signed 类型的,最大只能存 2147483647行记录 。 处理过程: 增加DBLE中间件代......
    04-17
  • mysql外键基本功能与用法的介绍

    mysql外键基本功能与用法的介绍

    本文内容: 什么是外键 外键的增加 外键的修改和删除 外键的约束模式 首发日期:2018-04-12 什么是外键: 外键就是表中存在一个 字段 指向 另外一个表的主键 ,那么这个字段就可以称为外键。 一张表可以有多个外键。 外键用于约束表与表......
    04-15
  • mysql语句书写和执行顺序的介绍

    mysql语句书写和执行顺序的介绍

    mysql语句的书写顺序和执行顺序有很大差异。 书写顺序,mysql的一般书写顺写为: select 要返回的数据列 from 表名 join, left join, right join... join join表 on join条件 where where条件 group by 分组条件 having 分组后的筛选条件......
    03-27
  • 详解MySQL union all与union的区别

    详解MySQL union all与union的区别

    union 是对数据进行并集操作,不包括重复行,同时进行默认排序Union all 是对数据进行并集操作,包括重复行,不进行排序举例说明: 创建数据库表: ? 1 2 3 4 5 6 7 CREATE TABLE `t_demo` ( `id` int (32) NOT NULL , ` name ` varchar ......
    03-26
  • MySQL case when使用方法的介绍

    MySQL case when使用方法的介绍

    首先我们创建数据库表: CREATE TABLE `t_demo` ( `id` int(32) NOT NULL, `name` varchar(255) DEFAULT NULL, `age` int(2) DEFAULT NULL, `num` int(3) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 插入数......
    03-26
  • SQL注入漏洞过程实例及解决方案

    SQL注入漏洞过程实例及解决方案

    代码示例: public class JDBCDemo3 { public static void demo3_1(){ boolean flag=login(aaa OR ,1651561); //若已知用户名,用这种方式便可不用知道密码就可登陆成功 if (flag){ System.out.println(登陆成功); }else{ System.out.pri......
    03-21

最新更新