我有一个用户登录和注销戳的列表。遗憾的是,LOGIN条目后面可能并不总是紧跟着LOGOUT条目
当按[event_date]排序时,我希望删除与前一行具有相同[ivent][user_id]
示例表
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'}
;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
使用SQL Server的ROW_NUMBER功能将是的一个选项
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
我的理解是,您希望删除条目,使模式始终为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
的索引。
注意:第一个版本不处理两个事件具有相同时间戳的可能性。然而,后者确实如此。
如果必须删除重复的行。那么就不需要通过子句来设置顺序了。
尝试低于
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