Sql 提取每2个样本之间时间差最小的数据
我有一张带有样本时间戳的表格:Sql 提取每2个样本之间时间差最小的数据,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,我有一张带有样本时间戳的表格: create table #OREN_TEMP(TS datetime) insert into #OREN_TEMP(TS) values ('2019-10-25 06:20:07.000'), ('2019-10-25 06:20:15.000'), ('2019-10-25 06:20:19.000'), ('2019-10-25 06:20:26.000'), ('2019-10-25 06:20:26
create table #OREN_TEMP(TS datetime)
insert into #OREN_TEMP(TS)
values
('2019-10-25 06:20:07.000'),
('2019-10-25 06:20:15.000'),
('2019-10-25 06:20:19.000'),
('2019-10-25 06:20:26.000'),
('2019-10-25 06:20:26.000'),
('2019-10-25 06:20:34.000'),
('2019-10-25 06:20:42.000'),
('2019-10-25 06:20:51.000'),
('2019-10-25 06:20:59.000'),
('2019-10-25 06:21:07.000'),
('2019-10-25 06:21:15.000'),
('2019-10-25 06:21:19.000'),
('2019-10-25 06:21:26.000')
select * from #OREN_TEMP
当一个样本到另一个样本之间的最短时间为20秒时,我被要求从表中提取数据。
这意味着我需要提取以下内容:
('2019-10-25 06:20:07.000')
('2019-10-25 06:20:34.000')
('2019-10-25 06:20:59.000')
('2019-10-25 06:21:19.000')
declare @MIN_DATE datetime
select top 1 @MIN_DATE =TS from #OREN_TEMP
order by TS
select TS
from (select TS, row_number() over (partition by datediff(second,@MIN_DATE,TS) / 20 order by TS) as RowNum
from #OREN_TEMP
) TMP
where TMP.ROWNUM=1
我试着做到以下几点:
('2019-10-25 06:20:07.000')
('2019-10-25 06:20:34.000')
('2019-10-25 06:20:59.000')
('2019-10-25 06:21:19.000')
declare @MIN_DATE datetime
select top 1 @MIN_DATE =TS from #OREN_TEMP
order by TS
select TS
from (select TS, row_number() over (partition by datediff(second,@MIN_DATE,TS) / 20 order by TS) as RowNum
from #OREN_TEMP
) TMP
where TMP.ROWNUM=1
我得到:
TS
2019-10-25 06:20:07.000
2019-10-25 06:20:34.000
2019-10-25 06:20:51.000 -- Not good - only 17 seconds from previous
2019-10-25 06:21:07.000 -- Not good - only 16 seconds from previous
但这并没有起到任何作用,因为我根据第一个TS划分时间框架,而不是根据最后一个TS划分时间框架
我想避免循环或光标。与表本身的内部联接是正常的
我该怎么做?
我使用的是SQL server 2012标准版。您可以为此使用递归CTE。但是它在SQLServer中效率不高。SQL Server对递归CTE有许多限制,包括子查询中没有聚合和递归引用 因此,这里有一个版本:
with first_row as (
select top (1) ot.*
from oren_temp ot
order by ts asc
),
cte as (
select ts, 1 as lev
from first_row
union all
select ot.ts, lev + 1
from oren_temp ot join
cte
on ot.ts >= dateadd(second, 20, cte.ts)
)
select lev, min(ts)
from cte
group by lev;
不过,我要提醒您不要在行太多的数据集上运行此操作
编辑:
实际上,有一种更有效的方法。在每个递归步骤中,我们可以使用row\u number()
保留前一个最先找到的ts
(这是最小值):
对于较大的数据,这应该更有效。而且,它也很酷。我的答案像@Gordon,但是独立制作的 我又用了cte
;with cte as (
-- got first row , mark it RowNumber = 1
select top 1 ts, RN = 1
from #OREN_TEMP
union all
-- in recursive part set number for all rows
select T.ts, convert(int,row_number() over ( order by T.TS))
from #OREN_TEMP T
-- join only to rows which are after 20+ secs
join cte T1 on datediff(SECOND,T1.TS, T.TS) >= 20
-- and we have to take RowNumber = 1 from cte
and T1.RN = 1
)
-- and result goes.......
select TS from cte
where RN = 1
结果
ts
-----------------------
2019-10-25 06:20:07.000
2019-10-25 06:20:34.000
2019-10-25 06:20:59.000
2019-10-25 06:21:19.000
编辑
对于像我(俄罗斯)这样的国家,要运行插入,我们必须使用命令预先编写代码
SET DATEFORMAT mdy
你看过
领先
或滞后
吗?谢谢戈登。它正在工作!!!你能解释一下为什么在递归内部和外部需要“where seqnum=1”吗?非常欢迎对代码进行简要解释。@oren。事实上,我想是的。在递归的每一步中,都有许多行出现或超过20秒的限制。seqnum=1
在下一轮递归中进行过滤,只考虑第一行。