SQL-запрос для удаления записей, происходящих в пределах 3000 миллисекунд друг от друга - PullRequest
2 голосов
/ 22 октября 2010

У меня есть таблица данных записи определенных пользовательских событий. Результаты выглядят примерно так:

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

Как я могу это сделать?

Ответы [ 4 ]

2 голосов
/ 22 октября 2010

Вы можете использовать цикл 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

Это печатает:

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.537
6   UserB       2010-10-21 18:47:33.373
1 голос
/ 22 октября 2010

Если мы удаляем эти результаты из набора результатов, и события каждого пользователя обрабатываются отдельно, тогда работают следующие (кража таблицы defn из ответа Andomar):

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

Если вам нужнона самом деле удалить, затем вы можете удалить из таблицы, где идентификатор не в (выберите идентификатор из последовательности)

0 голосов
/ 22 октября 2010

Вы можете написать процедуру, чтобы сделать это, перебирая события в порядке даты и сравнивая значение предыдущего события с текущим, используя DATEDIFF. Если это активная система, и ваша цель состоит в том, чтобы предотвратить дублирование журналов событий, было бы более целесообразно использовать триггер для предотвращения вставки любого нового события аналогичным образом.

0 голосов
/ 22 октября 2010

Под предыдущим событием вы подразумевали вставку? Почему бы не взять временную шкалу за основу?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...