我的表格中包含ID
,CHAR
和DATETIME
字段。现在我想得到所有行,DATEDIFF
为5分钟或更短。
参考样本数据:
ID2 CHA Timer
1 B 2018-03-06 11:31:39
2 S 2018-03-06 11:33:39
3 B 2018-03-06 11:39:39
4 S 2018-03-06 11:45:39
5 B 2018-03-06 11:46:39
6 S 2018-03-06 11:47:39
7 B 2018-03-06 11:48:39
8 S 2018-03-06 11:50:39
9 B 2018-03-06 11:51:39
10 S 2018-03-06 11:59:39
期望的输出:
ID2 CHA Timer
1 B 2018-03-06 11:31:39
2 S 2018-03-06 11:33:39
4 S 2018-03-06 11:45:39
5 B 2018-03-06 11:46:39
6 S 2018-03-06 11:47:39
7 B 2018-03-06 11:48:39
8 S 2018-03-06 11:50:39
9 B 2018-03-06 11:51:39
我目前的疑问是:
select *
from t t1
inner join t t2
on t1.ID = t2.ID
where datediff(minute, t1.timer, t2.timer)<=5
可悲的是,这个多次返回相同的条目。我认为这是因为INNER JOIN
而发生的,但我无法确定。
如何获得所需的结果?
Sqlfiddle自己测试一下。
答案 0 :(得分:2)
<强>更新强>
以下是使用更新数据的新解决方案。
SELECT *
FROM t AS t1
WHERE EXISTS
( SELECT 1
FROM t AS t2
WHERE ( t1.timer <= DATEADD( MINUTE, 5, t2.timer )
OR t1.timer >= DATEADD( MINUTE, -5, t2.timer ))
AND t1.id <> t2.id)
;
这将返回在其之前或之后的5分钟内发生的另一行的任何行。如果您使用大量数据运行此查询,则应该能够在timer
列上使用索引。
陈旧的答案
你非常接近。您需要加入字符字段,除非ID匹配。
select t2.*
from t t1
inner join t t2
on t1.cha = t2.cha
and t1.id <> t2.id
where datediff(minute, t1.timer, t2.timer) <=5
order by t2.id;
答案 1 :(得分:2)
您可以使用LEAD
和LAG
窗口函数:
select id, cha, timer
from (
select id, cha, timer,
COALESCE(datediff(minute,
lag(timer) over (order by id),
timer)
, 10) prev_diff,
COALESCE(datediff(minute,
timer,
lead(timer) over (order by id))
, 10) next_diff
from t) as x
where prev_diff <= 5 or next_diff <= 5
LEAD
用于获取 next 记录的timer
值,而LAG
用于获取 previous <的值/ em>记录。如果当前值与这两个值中的任何一个之间的差异等于或小于5
,那么您就匹配了。
<强>更新强>
如果id
字段无法用于确定行顺序,则您可以使用ROW_NUMBER
生成的数字代替:
;with t_rn AS (
select id, cha, timer,
row_number() over (order by timer) as rn
from t
)
select id, cha, timer
from (
select id, cha, timer,
coalesce(datediff(minute,
lag(timer) over (order by rn),
timer)
, 10) prev_diff,
coalesce(datediff(minute,
timer,
lead(timer) over (order by rn))
, 10) next_diff
from t_rn) as x
where prev_diff <= 5 or next_diff <= 5
感谢@Vladimir,他可以看到显而易见的地方,上面的查询可以简化为:
select id, cha, timer
from (
select id, cha, timer,
coalesce(datediff(minute,
lag(timer) over (order by timer),
timer)
, 10) prev_diff,
coalesce(datediff(minute,
timer,
lead(timer) over (order by timer))
, 10) next_diff
from t_rn) as x
where prev_diff <= 5 or next_diff <= 5
答案 2 :(得分:0)
好吧,您可以CROSS JOIN
代替INNER JOIN
。
select *
from t t1
cross join t t2
where
ABS(datediff(minute, t1.timer, t2.timer))<=5
AND t1.id < t2.id
这将给出所有可能的行对,其时间差小于5分钟。
t1.id < t2.id
只需要返回每对中的一个实例。
如果您对这样的配对不感兴趣,那么,您只需要将配对的每一面都放在一个列表中。 UNION
将删除重复项。
WITH
CTE_Pairs
AS
(
select
T1.id AS id1
,T1.cha AS cha1
,T1.timer AS timer1
,T2.id AS id2
,T2.cha AS cha2
,T2.timer AS timer2
from t t1
cross join t t2
where
ABS(datediff(second, t1.timer, t2.timer)) <= 5*60
AND t1.id < t2.id
)
SELECT
id1 AS id
,cha1 AS cha
,timer1 AS timer
FROM CTE_Pairs
UNION
SELECT
id2 AS id
,cha2 AS cha
,timer2 AS timer
FROM CTE_Pairs
ORDER BY id
;
答案 3 :(得分:0)
这应该可以解决问题
select distinct t1.*
from t t1
inner join t t2
on t1.ID <> t2.ID
where datediff(minute, t1.timer, t2.timer) between -5 and 5