MySQL计算相邻两行某列差值的方法
简述
博主最近因工作任务缠身,都无暇顾及到我的这片自留地了。前段时间稍有空闲,花了较多的精力学习《啊哈算法》,从中学习到很多之前没有太注重的内容,收益颇丰。但是这些算法题目还没有看完,等后面有时间了,还需重新自我温习一下前面所写的内容,并且继续耕耘后面的算法知识。
今天稍微有点时间,总结一下博主近期工作中所遇到的一些难题,希望借此机遇总结一下类似问题的解决方法,也算是一种积累吧。
背景
我们在司机的手机APP里预置了定时上报GPS数据的功能,功能设置为了APP每15秒收集一次GPS定位地址,然后每收集到10次就上报到服务器端持久化。但因为APP非安卓系统集成,而是由我方自主提供并设计了此功能,那么GPS数据的收集就有可能因司机人为操作或者其他网络等的影响,产生定位偏差或者获取定位失败的情况。现在我们服务端就有这么一个需求,要求分析出安装在司机手机中的APP是否定期收集到了GPS位置。
为了保证GPS定位数据能够较为顺利的上传到服务器端,我们在APP每次请求完服务器端之后,只有当APP接收到来自服务器的正确回应,才能表示这次上传数据是正常且准确的,然后清空掉APP端上一次记录的GPS定位数据;但是如果APP因为各种原因无法将上一次收集的数据上报的服务器端,再尝试一番之后无果,将会在下一次与下一批收集到的数据一同上报,通过此机制来保证数据传递的稳定性。
分析
如果司机手机中的APP是定时15秒就收集到GPS地址的话,那么持久化到数据库中按获取时间顺序排列的前后两条记录的时间差应该就是15秒了,如果大于了15秒,那么就说明定时获取出现了问题。那么现在我们要做的,就是筛选出前后两条记录在获取GPS位置的时间差是否大于15秒,计算时间差的方法在MySQL中已经有了,那就是TimeDiff(对于TimeDiff在Java中使用的小坑我前面的博文有所总结,有兴趣的朋友可以Mark一下,后面抽时间看看。),而对于计算前后两条记录怎么计算差值,这好像确实没有接触过,那么本篇文章就来解决这个问题。
传送门:SQL函数TIMEDIFF在Java程序中使用报错的问题分析
https://www.cnblogs.com/captainad/p/10855608.html
解决
首先博主在服务端有一个表来记录司机上报上来的GPS点位信息,表结构如下:
-- 司机GPS收集表
CREATE TABLE captainad_driver_gps_position (
id BIGINT NOT NULL auto_increment COMMENT '主键',
business_id BIGINT DEFAULT NULL COMMENT '业务ID',
device_mac VARCHAR (64) DEFAULT NULL COMMENT '设备MAC地址',
device_imei VARCHAR (64) DEFAULT NULL COMMENT '设备IMEI',
lat_lng VARCHAR (64) DEFAULT NULL COMMENT '纬经度',
capture_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '捕获时间',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (id),
KEY `idx_business_id` (`business_id`) USING BTREE
) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '司机GPS收集';
表中记录的数据大致如下:

现在就对按获取GPS位置的时间capture_time在按照时间排序之后,进行前后两条记录计算差值。为了计算两者的差值,那么我们肯定是需要获取到一前一后两条记录的,这里我们可以巧用一个变量来记录当前行的行数,然后随着循环查询每次将行数叠加,以达到行记录的目的,这样一来,我们就能知道哪两条记录是一前一后的了。
打印行号的SQL语句:
SELECT
(@rownum := @rownum + 1) AS rownum,
tab.business_id,
tab.device_mac,
tab.capture_time
FROM
captainad_driver_gps_position tab,
(SELECT @rownum := 0) r -- 声明变量
WHERE
1 = 1
AND DATE_FORMAT(
tab.capture_time,
'%Y-%m-%d'
) = '2019-06-28'
ORDER BY
tab.capture_time
基于此,我们将目标SQL给写出来,这里我根据我们的实际业务将语句稍微做了整理,脚本大致如下:
SELECT
t.business_id,
t.device_mac,
t.capture_time,
t.tdiff
FROM
(
SELECT
r1.business_id,
r1.device_mac,
r1.capture_time,
TIMEDIFF(
r2.capture_time,
r1.capture_time
) AS 'tdiff'
FROM
(
SELECT
(@rownum := @rownum + 1) AS rownum,
tab.business_id,
tab.device_mac,
tab.capture_time
FROM
captainad_driver_gps_position tab,
(SELECT @rownum := 0) r
WHERE
1 = 1
AND DATE_FORMAT(
tab.capture_time,
'%Y-%m-%d'
) = '2019-06-28'
ORDER BY
tab.capture_time
) r1
LEFT JOIN (
SELECT
(@INDEX := @INDEX + 1) AS rownum,
tab.business_id,
tab.device_mac,
tab.capture_time
FROM
captainad_driver_gps_position tab,
(SELECT @INDEX := 0) r
WHERE
1 = 1
AND DATE_FORMAT(
tab.capture_time,
'%Y-%m-%d'
) = '2019-06-28'
ORDER BY
tab.capture_time
) r2 ON r1.business_id = r2.business_id
AND r1.device_mac = r2.device_mac
AND r1.rownum = r2.rownum - 1
) t
WHERE
t.tdiff > '00:00:15'
在上面的代码中,我们通过 r1.rownum = r2.rownum - 1来判断两条记录是否是前后行,然后再使用TIMEDIFF函数来计算时间差,到此,我们的目标就实现了。
MySQL计算相邻两行某列差值的方法的更多相关文章
- php 日期 - 计算2个日期的差值
		/** * 日期-计算2个日期的差值 * @return int */ public function get_difference($date, $new_date) { $date = strto ... 
- C 语言实例 - 计算两个时间段的差值
		C 语言实例 - 计算两个时间段的差值 C 语言实例 C 语言实例 计算两个时间段的差值. 实例 #include <stdio.h> struct TIME { int seconds; ... 
- oracle计算两个时间的差值(XX天XX时XX分XX秒)
		在工作中需要计算两个时间的差值,结束时间 - 开始时间,又不想在js里写function,也不想在java里去计算,干脆就在数据库做了一个函数来计算两个时间的差值.格式为XX天XX时XX分XX秒: 上 ... 
- 【HANA系列】SAP HANA SQL计算两个日期的差值
		公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL计算两个 ... 
- javascript 计算两个日期的差值
		代码 Typescript版 /** * TimeSpan just like the class TimpSpan in C# ,represent the time difference * @c ... 
- MySQL 批量修改某一列的值为另外一个字段的值
		mysql> select * from fruit; +----+--------+-------+ | id | name | price | +----+--------+-------+ ... 
- 用Scala实现集合中相邻元素间的差值
		欢迎转载,转载请注明出处,徽沪一郎. 概要 代码这东西,不写肯定不行,新学Scala不久,将实际遇到的一些问题记录下来,日后也好查找. 今天讲的是如何计算同一集合中元素两两之间的差值,即求开始集合(a ... 
- mysql获取插入时自增ID值的方法
		1. LAST_INSERT_ID: LAST_INSERT_ID 是与table无关的,如果向表a插入数据后,再向表b插入数据,LAST_INSERT_ID会改变. LAST_INSERT_ID是 ... 
- JavaScript获取table中某一列的值的方法
		1.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ... 
随机推荐
- linux 实时监控网速脚本(转)
			#!/bin/bash ethn=$ while true do RX_pre=$(cat /proc/net/dev | grep $ethn | sed 's/:/ /g' | awk '{pri ... 
- UDP用于保持大量终端的在线与控制,应用与业务则通过TCP去实现。这个和FTP服务控制与数据分离,采取不同的连接,有异曲同工之处 端口映射老化时间
			移动端IM/推送系统的协议选型:UDP还是TCP? http://www.52im.net/thread-33-1-1.html 
- JDBC 线程安全 数据库连接池
			jdbc 是线程安全的,但是,推荐一个线程用一个链接 JDBC is thread safe: It is quite OK to pass the various JDBC objects betw ... 
- 2019 GDD  breaking world‘s record of π
			Day 2 1.breaking pi‘s world record with google cloud [concept] memory wall: Originally theorized in ... 
- Cassandra开发入门文档第一部分
			Cassandra的特点 横向可扩展性: Cassandra部署具有几乎无限的存储和处理数据的能力.当需要额外的容量时,可以简单地将更多的机器添加到集群中.当新机器加入集群时,Cassandra需要对 ... 
- python自动化接口测试
			前几天,同组妹子说想要对接口那些异常值进行测试,能否有自动化测试的方法.仔细想了一下,工具还挺多,大概分析了一下: 1.soapui:可以对接口参数进行异常值参数化,可以加断言,一般我们会加httpc ... 
- tracking.js实现前端人脸识别
			1.下载https://trackingjs.com/ 2.运行例子 纳总一下 发现效果 里面的代码为 <!doctype html><html><head> &l ... 
- spark 性能优化简要总结
			1.从同一个数据源尽量只创建一个rdd,后续业务逻辑复用该rdd2.如果要对某个rdd进行多次的transformation或action操作,应当持久化该rdd3.从数据源读取到rdd后,要尽早的进 ... 
- 使用事件和 CQRS 重写 CRUD 系统
			使用事件和 CQRS 重写 CRUD 系统 https://msdn.microsoft.com/zh-cn/magazine/mt790196.aspx https://github.com/mem ... 
- 手把手教你创建electron+vue项目
			electron可以结合前端的很多框架来进行快速的开发.在这里只讲一种electron结合vue并且使用前端的elementui来快速搭建一个项目页面. 第一步.创建electron 以管理员身份运行 ... 
