【数据库】【算法】从一串数据中获取符合某个条件的时间区间

算法背景

在项目中,经常要看到这么一个要求:从一组根据时间排列的数据,要求计算出其中满足某个条件的一串数据,求这串数据的开始与结束时间.

比如说,用小米手环采集到一组用户的心率数据,要求算出其中有多长时间用户的心率>100.

比如说,通过Gps定位获取到车辆的行驶数据,按要求速度超过80就算超速,那么在这组数据中,车辆超速了多长时间.

在数据采集非常方便的时代,像以上的场景及需求比比皆是.

要算出所要求的结果,当然可以写个计算器,一条一条分析过去,但是这样的话效率非常慢.

更多时候还是要求在数据库中直接通过SQL算出结果。

因此我觉得这个算法非常有价值。

 假设具体场景

具体一点,比如下面这串数据:

按照下面的条件将以上数据进行分段切割,

Speed >= 0 且 Speed < 30

Speed >= 30 且 Speed < 60

Speed >= 60 且 Speed < 80

Speed >= 80

并且算出每段数据的开始时间与结束时间,开始SOC与结束SOC.

思路

1.先取到原始数据

;WITH temp AS (
	SELECT ROW_NUMBER() OVER (ORDER BY Car,Time ASC)AS ID,  Time,Car,SOC
		,SpeedFlg = CASE  WHEN  Speed >= 0 AND Speed < 30 THEN 1
						  WHEN  Speed >= 30 AND Speed < 60 THEN 2
						  WHEN  Speed >= 60 AND Speed < 80 THEN 3
						  WHEN  Speed >= 80 THEN 4
						  END
	FROM OrigData
	WHERE Car = ‘ABCDEFK10NZ000001‘
	AND Time >= ‘2016-06-01‘
	AND Time <= GETDATE()
)

先把上面的整串数据取到.

2.对数据进行排序,算出每个分段的开始于结束时间,并过滤掉分段中部的数据,保留分段的开始结束数据

final as(
	SELECT ROW_NUMBER()OVER(ORDER BY a.Car ) as tid,*
	FROM (
		SELECT a.Car,a.SpeedFlg,A.SOC
			,begintime = CASE WHEN A.ID = 1 OR b.SpeedFlg IS NULL THEN A.Time END
			,endtime = CASE WHEN c.SpeedFlg IS NULL THEN A.Time END
		FROM  temp a
		LEFT JOIN temp b ON a.ID = b.ID +1 AND B.SpeedFlg = A.SpeedFlg
		LEFT JOIN temp c ON a.ID = c.ID - 1  AND C.SpeedFlg = A.SpeedFlg
	)A
	where begintime is not null
	or endtime is not null
)

根据上面的算法,可以得出以下数据

3.将每个分段的开始结束数据进行合并,得到一个完整的数据

select a.Car
	,SpeedFlg = case a.SpeedFlg when 1 then ‘0-30‘
								when 2 then ‘30-60‘
								when 3 then ‘60-80‘
								when 4 then ‘80以上‘
								end
	,a.begintime,b.endtime,a.SOC as beginsoc ,b.SOC as endsoc
from final a
INNER JOIN final b on a.Car = b.Car and a.SpeedFlg = b.SpeedFlg and a.tid = b.tid - 1

最终得到下面这串数据

点开可查看完整代码:

;WITH temp AS (
	SELECT ROW_NUMBER() OVER (ORDER BY Car,Time ASC)AS ID,  Time,Car,SOC
		,SpeedFlg = CASE  WHEN  Speed >= 0 AND Speed < 30 THEN 1
						  WHEN  Speed >= 30 AND Speed < 60 THEN 2
						  WHEN  Speed >= 60 AND Speed < 80 THEN 3
						  WHEN  Speed >= 80 THEN 4
						  END
	FROM OrigData
	WHERE Car = ‘ABCDEFK10NZ000001‘
	AND Time >= ‘2016-06-01‘
	AND Time <= GETDATE()
),
final as(
	SELECT ROW_NUMBER()OVER(ORDER BY a.Car ) as tid,*
	FROM (
		SELECT a.Car,a.SpeedFlg,A.SOC
			,begintime = CASE WHEN A.ID = 1 OR b.SpeedFlg IS NULL THEN A.Time END
			,endtime = CASE WHEN c.SpeedFlg IS NULL THEN A.Time END
		FROM  temp a
		LEFT JOIN temp b ON a.ID = b.ID +1 AND B.SpeedFlg = A.SpeedFlg
		LEFT JOIN temp c ON a.ID = c.ID - 1  AND C.SpeedFlg = A.SpeedFlg
	)A
	where begintime is not null
	or endtime is not null
) 

select a.Car
	,SpeedFlg = case a.SpeedFlg when 1 then ‘0-30‘
								when 2 then ‘30-60‘
								when 3 then ‘60-80‘
								when 4 then ‘80以上‘
								end
	,a.begintime,b.endtime,a.SOC as beginsoc ,b.SOC as endsoc
from final a
INNER JOIN final b on a.Car = b.Car and a.SpeedFlg = b.SpeedFlg and a.tid = b.tid - 1

  

时间: 2024-10-12 08:09:51

【数据库】【算法】从一串数据中获取符合某个条件的时间区间的相关文章

java . 请在小于99999的正整数中找符合下列条件的数,它既是完全平方数,又有两位数字相同,如:144,676。

1 import java.util.HashMap; 2 import java.util.Map; 3 import java.util.Map.Entry; 4 //请在小于99999的正整数中找符合下列条件的数,它既是完全平方数, 5 //又有两位数字相同,如:144,676. 6 public class wqs { 7 8 //完全平方数 9 public static boolean iswqs(int n){ 10 int i; 11 double dn=Math.sqrt(n)

从Wos文本数据中获取摘要进行分析的一种方法

namespace 清理数据 { class Program { static void Main(string[] args) { string strDirName = "File"; int iWriteFlag = 0; if (Directory.Exists(strDirName)) { string[] strFiles = Directory.GetFiles(strDirName); foreach (var item in strFiles) { using (va

jquery输出ajax返回数据中的时间戳转化为日期时间的函数

//第一种 function getLocalTime(nS) { return new Date(parseInt(nS) * 1000).toLocaleString().replace(/:\d{1,2}$/,' '); } alert(getLocalTime(1293072805)); //结果是2010年12月23日 10:53 //第二种 function getLocalTime(nS) { return new Date(parseInt(nS) * 1000).toLocal

求一串数中的最值(空间换时间)

求最值 2014年9月19日 16:44:28 这只是个例子,可看明白了? 1 foreach (CircleInfo p in point) 2 { 3 //找出出现次数最多的数 4 allnum++; 5 temp = p.Diameter; 6 count[temp]++; 7 if (count[temp] > maxNum) 8 { 9 maxNum = count[temp]; 10 most = temp; 11 } 12 }

C++中如何在顺序容器中删除符合特定条件的元素

以前很少做删除操作,vector一直当成数组用,而实际追求效率时又经常舍弃vector选用C风格数组.看<C++ Primer>到顺序容器删除这节时试着实现课后习题结果一动手我就出错了. 习题是将数组int ia[]拷贝到std::vector<int>中,并删除偶数元素. 先给出我的错误代码 int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 }; vector<int> v(begin(ia), end(ia)); fo

【转载】Hibernate---在Hibernate中获取数据方式与缓存使用

原文地址:http://www.blogjava.net/pengpenglin/archive/2010/03/15/315440.html Hibernate获取数据的方式有不同的几种,其与缓存结合使用的效果也不尽相同,而Hibernate中具体怎么使用缓存其实是我们很关心的一个问题,直接涉及到性能方面. 缓存在Hibernate中主要有三个方面:一级缓存.二级缓存和查询缓存 ①一级缓存在Hibernate中对应的为session范围的缓存,也就是当session关闭时缓存即被清除,一级缓存

iOS开发中如何将后台返回的时间转换为常见字串

在iOS开发中,经常需要从后台数据中获取时间,但是此时后台返回的时间格式经常是一串类似"123456789"的数字,此数字是1970年开始截至到现在的秒数,此时我们需要将其转换为可以用的格式. 模型中我定义了c_time属性,通过重写c_time的get方法中进行格式的转换. - (NSString *)c_time{ // 1.创建时间格式化类 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; // 2.设置时间

Hadoop之——MapReduce实现从海量数字信息中获取最大值

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46287805 通过Hadoop的自定义排序算法可实现从海量数字中获取最大值,不多说,直接上代码 1.Mapper类的实现 static class MyMapper extends Mapper<LongWritable, Text, LongWritable, NullWritable>{ long max = Long.MIN_VALUE; protected void m

python从数据库中获取utf8格式的中文数据输出时变成问号或乱码

我用python操作mysql数据库,数据库中数据格式为utf8,我使用python调用select语句后获取到数据库的信息,然后使用print打印出来的时候,原本中文数据却无法显示,显示出来的是一串?,为了解决这个问题,我也是绞尽脑汁啊. 我在网上搜集了很多资料,大家都说是windows默认的格式是'GBK',输出从mysql数据库中获取到的中文数据时,需要这样写: 假设info是从数据库中获取的中文值 print info.decode('UTF-8').encode('GBK') 结果: