Удалить строки после дубликата - PullRequest
5 голосов
/ 25 мая 2011

У меня есть список марок для входа и выхода пользователя.К сожалению, запись LOGIN не всегда может сопровождаться записью LOGOUT.
Я хочу удалить любую строку, имеющую такие же [event] и [user_id] , как предыдущая строка, когдаупорядочено по [event_date] Есть предложения, как это сделать?

Пример таблицы

CREATE TABLE #LOG (
    [id] int IDENTITY(1,1),
    [user_id] int,
    [event] varchar(50),
    [event_date] datetime
);
INSERT INTO #LOG ([user_id], [event], [event_date])
SELECT 1,'LOGIN',{ts '2010-12-15 15:31:59'}
UNION ALL SELECT 1,'LOGOUT',{ts '2010-12-15 15:32:55'}
UNION ALL SELECT 1,'LOGIN',{ts '2010-12-15 15:38:04'}
UNION ALL SELECT 1,'LOGOUT',{ts '2010-12-15 15:38:17'}
UNION ALL SELECT 1,'LOGOUT',{ts '2010-12-15 15:38:45'} -- Delete
UNION ALL SELECT 2,'LOGIN',{ts '2010-12-15 16:59:39'}
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:00:08'}
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:00:39'} -- Delete
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:01:16'} -- Delete
UNION ALL SELECT 2,'LOGIN',{ts '2010-12-15 17:01:38'}
UNION ALL SELECT 2,'LOGIN',{ts '2010-12-15 17:02:26'} -- Delete
UNION ALL SELECT 2,'LOGOUT',{ts '2010-12-15 17:02:39'}

Ответы [ 4 ]

3 голосов
/ 25 мая 2011
;WITH T1 AS
(
SELECT * , 
        ROW_NUMBER() OVER (ORDER BY event_date)-
        ROW_NUMBER() OVER (PARTITION BY [user_id], [event] 
                               ORDER BY event_date) AS Grp
FROM #LOG
),T2 AS
(
SELECT 
   ROW_NUMBER() OVER (PARTITION BY [user_id], [event], Grp 
                          ORDER BY event_date) RN
FROM T1
)
DELETE FROM T2 
WHERE RN > 1
2 голосов
/ 25 мая 2011

Использование функциональности ROW_NUMBER SQL Server может быть вариантом

Оператор SQL

;WITH q AS (
    SELECT  Rownumber = ROW_NUMBER() OVER (ORDER BY user_id, event_date)
    , user_id
    , event
    , event_date
    FROM    #LOG
)
DELETE FROM #LOG
FROM    #LOG l
        INNER JOIN (
            SELECT  q2.*
            FROM    q q1
                    INNER JOIN q q2 ON  q2.Rownumber = q1.Rownumber + 1
                                        AND q2.user_id = q1.user_id
                                        AND q2.event = q1.event
        ) q ON  q.user_id = l.user_id
                AND q.event_date = l.event_date

SELECT  *
FROM    #LOG
2 голосов
/ 25 мая 2011

Насколько я понимаю, вы хотите удалить записи так, чтобы шаблон всегда был In,Out,In,Out,etc.

Это означает, что запись удаляется, если предыдущая запись (когда порядок по user_id, затем event_date) имеетодно и то же событие.

Есть два варианта, которые я хотел бы использовать для этого ...

DELETE
  #log
WHERE
  event = (
           SELECT
             TOP 1
             event
           FROM
             #log AS [preceding]
           WHERE
             [preceding].user_id = #log.user_id
             AND [preceding].event_date < #log.event_date
           ORDER BY
             [preceding].event_date DESC
          )

Или ...

WITH ordered_log AS (
  SELECT
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_date) AS user_event_id,
    *
  FROM
    #log
)

DELETE
  ordered_log
FROM
  ordered_log
INNER JOIN
  ordered_log   AS [preceding]
    ON  [preceding].login_id      = [ordered_log].login_id
    AND [preceding].user_event_id = [ordered_log].user_event_id - 1
WHERE
  [preceding].event = [ordered_log].event

В любом случае,Я настоятельно рекомендую индекс, охватывающий user_id, затем event_date.


Примечание: Первая версия не справляется с возможностью двух событий, имеющихта же временная метка.Последний, однако, делает.

0 голосов
/ 25 мая 2011

Если вам нужно удалить дубликат строки. Тогда нет необходимости устанавливать порядок по пункту.

Попробуйте ниже

Delete l from #LOG l
Inner Join 
(
    Select id from #LOG l
    Inner Join(
        Select user_id, event from #LOG 
        group by user_id, event
        having COUNT(user_id) > 1 and COUNT(event) > 1
    )T
    on (l.user_id = t.user_id) and (l.event = t.event)
)T
on T.id = l.id
...