SQL查询以删除相互间隔3000毫秒内的记录

SQL查询以删除相互间隔3000毫秒内的记录,sql,sql-server-2008,Sql,Sql Server 2008,我有一个记录某些用户事件的数据表。结果如下所示: ID Username EventDate 1 UserA 2010-10-21 16:59:59.367 2 UserA 2010-10-21 17:00:00.114 3 UserA 2010-10-21 17:00:00.003 4 UserA 2010-10-21 17:00:02.867 5 UserB 2010-10-21 18:43:26.538 6

我有一个记录某些用户事件的数据表。结果如下所示:

ID    Username EventDate
1     UserA    2010-10-21 16:59:59.367
2     UserA    2010-10-21 17:00:00.114    
3     UserA    2010-10-21 17:00:00.003
4     UserA    2010-10-21 17:00:02.867
5     UserB    2010-10-21 18:43:26.538
6     UserB    2010-10-21 18:47:33.373
我想运行一个查询,删除前一个事件3000毫秒内发生的所有事件。请注意,毫秒是相关的

生成的表如下所示:

ID    Username EventDate
1     UserA    2010-10-21 16:59:59.367
4     UserA    2010-10-21 17:00:02.867
5     UserB    2010-10-21 18:43:26.538
6     UserB    2010-10-21 18:47:33.373

我怎样才能做到这一点?

之前的事件,您是指插入吗?为什么不以时间线为基准?

您可以编写一个过程,通过按日期顺序迭代事件,并使用DATEDIFF将前一个事件的值与当前事件的值进行比较来实现这一点。如果这是一个活动系统,并且您的目标是防止重复事件日志,那么使用触发器来防止以类似方式插入任何新事件将更有意义。

您可以使用while循环一次删除一行。这避免了多行之间的距离都在3秒内,而不是在第一行的3秒内的问题

例如:

declare @t table (ID int, Username varchar(50), EventDate datetime)
insert @t
          select 1,     'UserA',    '2010-10-21 16:59:59.367'
union all select 2,     'UserA',    '2010-10-21 17:00:00.114'    
union all select 3,     'UserA',    '2010-10-21 17:00:00.003'
union all select 4,     'UserA',    '2010-10-21 17:00:02.867'
union all select 5,     'UserB',    '2010-10-21 18:43:26.538'
union all select 6,     'UserB',    '2010-10-21 18:47:33.373'


while 1=1
    begin
    delete  @t
    where   ID =
            (
            select  top 1 t2.ID
            from    @t t2
            where   exists
                    (
                    select  *
                    from    @t t1
                    where   t1.Username = t2.Username
                            and t1.EventDate < t2.EventDate
                            and datediff(millisecond, t1.EventDate, 
                                         t2.EventDate) <= 3000
                    )
            )

    if @@ROWCOUNT = 0 
        break
    end

select * from @t

如果我们从结果集中删除这些结果,并且每个用户事件都被单独处理,那么下面的工作将从Andromar的答案中删除表defn:

declare @t table (ID int, Username varchar(50), EventDate datetime)
insert @t
          select 1,     'UserA',    '2010-10-21 16:59:59.367'
union all select 2,     'UserA',    '2010-10-21 17:00:00.114'    
union all select 3,     'UserA',    '2010-10-21 17:00:00.003'
union all select 4,     'UserA',    '2010-10-21 17:00:02.867'
union all select 5,     'UserB',    '2010-10-21 18:43:26.538'
union all select 6,     'UserB',    '2010-10-21 18:47:33.373'

;WITH PerUserIDs AS (
    SELECT ID,Username,EventDate,ROW_NUMBER() OVER (PARTITION BY Username ORDER BY EventDate) as R from @t
), Sequenced AS (
    SELECT ID,Username,EventDate,R from PerUserIDs where R = 1
    union all
    select pui.ID,pui.UserName,pui.EventDate,pui.R
    from
        Sequenced s
            inner join
        PerUserIDs pui
            on
                s.R < pui.R and
                s.Username = pui.Username and
                DATEDIFF(millisecond,s.EventDate,pui.EventDate) >= 3000
    where
        not exists(select * from PerUserIDs anti where anti.R < pui.R and s.R < anti.R and s.Username = anti.username and DATEDIFF(millisecond,s.EventDate,anti.EventDate)>= 3000)
)
select * from Sequenced order by Username,EventDate

如果确实需要删除,则可以从表中删除,其中ID不在select ID from Sequenced(从序列中选择ID)

中。如果要删除前一个事件后3000毫秒内发生的所有事件,则我假定该事件将被删除。是的,完全正确。这是棘手的部分。应该删除ID2和ID3,但它们也会在ID4的3000毫秒内出现。但是,ID 2和3出现在ID 1之后,因此应删除这些ID,而不考虑ID 4。这感觉像是一个开始的时刻。你是指从表中删除还是从结果集中删除?此外,由于您已经包含了Username列-我们是否单独处理每个用户事件,例如,我们是否删除UserA事件发生1秒后发生的UserB事件?所有记录首先按时间排序。从这里开始,我想查看第一条记录并删除3000毫秒内发生的任何后续记录。ID2和ID3都发生在ID1的3000毫秒内,因此它们应该被删除。我不想阻止重复条目。还有一些时候,我希望事件发生得非常紧密。我可以像你建议的那样编写一个过程,但遍历记录将是一个漫长的过程,我希望有一种简单/快速的方法。你能再解释一下情况吗?如果你需要定期这样做,那么我认为预防是比维护更好的解决方案。如果不是,那么运行一次清理过程的时间似乎无关紧要。这看起来不错。对性能有什么担心吗?我不是在看大量的数据,最多可能是10000行。如果性能是最重要的考虑因素,我认为只运行一个select,遍历行,将最后一个日期值保留在变量中,并将最后一个日期值与当前行进行比较会更快。如果最终删除了一行,请清除最后一个值,这样就不会出现多行一起删除的问题。这很有趣。我不想删除我需要更新问题的记录,所以这是一个很好的测试选项。我现在就去试一试。
declare @t table (ID int, Username varchar(50), EventDate datetime)
insert @t
          select 1,     'UserA',    '2010-10-21 16:59:59.367'
union all select 2,     'UserA',    '2010-10-21 17:00:00.114'    
union all select 3,     'UserA',    '2010-10-21 17:00:00.003'
union all select 4,     'UserA',    '2010-10-21 17:00:02.867'
union all select 5,     'UserB',    '2010-10-21 18:43:26.538'
union all select 6,     'UserB',    '2010-10-21 18:47:33.373'

;WITH PerUserIDs AS (
    SELECT ID,Username,EventDate,ROW_NUMBER() OVER (PARTITION BY Username ORDER BY EventDate) as R from @t
), Sequenced AS (
    SELECT ID,Username,EventDate,R from PerUserIDs where R = 1
    union all
    select pui.ID,pui.UserName,pui.EventDate,pui.R
    from
        Sequenced s
            inner join
        PerUserIDs pui
            on
                s.R < pui.R and
                s.Username = pui.Username and
                DATEDIFF(millisecond,s.EventDate,pui.EventDate) >= 3000
    where
        not exists(select * from PerUserIDs anti where anti.R < pui.R and s.R < anti.R and s.Username = anti.username and DATEDIFF(millisecond,s.EventDate,anti.EventDate)>= 3000)
)
select * from Sequenced order by Username,EventDate