2017-07-14 70 views
2

我有一個表中有事件,我需要找到重複的事件。問題是彼此之間發生1秒鐘的事件被認爲是重複的。所以,如果我的表有這些值Sql服務器:任何方式根據其他記錄的日期按日期分組記錄?

id | var1 | var2 | var3 | date 
1 | 1 | 2 | 3 | 2001-01-01 01:01:01.456 
2 | 1 | 2 | 3 | 2001-01-01 01:01:02.234 
3 | 1 | 2 | 3 | 2001-01-01 01:01:04.789 

記錄1和2被視爲重複,因爲他們是一秒鐘之內,但3是不是因爲它的後2

超過一秒鐘有什麼辦法寫一個查詢只選擇一系列重複中的​​第一條記錄?

編輯:也可能有行將不需要被重複捕獲。 Id是表的主鍵,不在匹配標準中使用;這只是爲了澄清。

+1

什麼,如果有對方的第二個中的三個記錄......只保留1?並且ID只是一個PK,這意味着var1,var2和var3應該被認爲是重複的?即如果它們不相同,那麼它不是重複的? – scsimon

+1

@scsimon是的。所有記錄var1,2和3是相同的,日期在1秒內,只能保留1條記錄。如果在該範圍內有2個或200個,則無關緊要。 Id是PK。 – RossD

+0

感謝@RossD的澄清。我剛剛編輯了我的答案,我*瘦*它應該在所有情況下工作。讓我知道如果它不。爲了清晰起見,我將它放在多個cte中。 – scsimon

回答

2

這裏,似乎像它應該爲你工作的方式。

一些假設:

  1. 我想重複的是不包括ID的實際行重複,根據您提供1秒條款。如果不是這種情況...刪除分區的部分row_number()窗口函數,它將改變行爲
  2. 這將刪除遞歸重複項。也就是說,如果3,4,甚至15排在彼此的一秒鐘內,它保持1
  3. 這應該不論工作,如果第一行或最後一行是重複

下面的代碼。取消註釋了兩行在表中看到的變化

declare @table table(id int, var1 int, var2 int, var3 int, date datetime2) 
insert into @table 
values 
--(0,1,2,3,'2001-01-01 00:01:01.456'), 

(1,1,2,3,'2001-01-01 01:01:01.456'), --dupe of 1/2/3 
(2,1,2,3,'2001-01-01 01:01:02.214'), --dupe of 1/2/3 
(3,1,2,3,'2001-01-01 01:01:02.234'), --dupe of 1/2/3 
(4,1,2,3,'2001-01-01 01:01:02.244'), --dupe of 1/2/3 

(5,1,2,3,'2001-01-01 01:01:04.789'), --dupe of 4/5 
(6,1,2,3,'2001-01-01 01:01:04.989'), --dupe of 4/5 

--(7,1,2,3,'2001-01-01 01:01:06.789'), --dupe of 6/7 
(8,1,2,3,'2001-01-01 01:01:06.799') --dupe of 6/7 

--apply the sequence 
;with cte as(
select 
    *, 
    ROW_NUMBER() over (partition by var1, var2, var3 order by date) as RN --just in case... change this to just order by id, date if need be and remove the partition 
from 
    @table), 

--get first/most of the batch to remove 
cte2 as(
select 
    c1.* 
    ,c2.RN as RowsToRemove 
from cte c1 
left join 
    cte c2 on c1.RN < c2.rn and 
    datediff(second,c1.date,c2.date) < 1), 


--remove the rows identified in the above cte 
cte3 as(
select distinct 
    ID, 
    var1, 
    var2, 
    var3, 
    date, 
    RN 
from cte2 
where 
    RN not in (select distinct isnull(RowsToRemove,0) from cte2)), 

--add another sequence. This is necessary for first/last row check for duplicate 
cte4 as(
select 
    f.*, 
    row_number() over (partition by var1, var2, var3 order by date) RN2 
from 
    cte3 f) 

--return the results 
select 
    f.ID, 
    f.var1, 
    f.var2, 
    f.var3, 
    f.date 
from 
    cte4 f 
left join 
    cte4 d on d.RN = f.RN - 1 
where isnull(datediff(second,d.date,f.date),500) > 1 

退貨

+----+------+------+------+-----------------------------+ 
| ID | var1 | var2 | var3 |   date    | 
+----+------+------+------+-----------------------------+ 
| 1 | 1 | 2 | 3 | 2001-01-01 01:01:01.4560000 | 
| 5 | 1 | 2 | 3 | 2001-01-01 01:01:04.7890000 | 
| 8 | 1 | 2 | 3 | 2001-01-01 01:01:06.7990000 | 
+----+------+------+------+-----------------------------+ 
2

滯後是一個可能的解決方案,這樣的事情:

select * from (
select *, lag(date,1) over(order by date) previoustime from yourtable 
) x 
where datediff(second,previoustime,date)<1 
0
select T1.date,... from MyTable T1 
left outer join MyTable T2 on cast(T1.date as date) = cast(T2.date as date) and 
datediff(second,T1.date,T2.date)<=1 
group by cast(T1.date as date)