删除 table 中共享相同 ID 的所有行
Deleting all rows from table that share the same ID
我有以下 table:
Name | ID | date |
Login | 1 | somedate |
Command | 1 | somedate |
Command | 1 | somedate |
Login | 2 | somedate |
Command | 1 | somedate |
Command | 2 | somedate |
Logout | 1 | somedate |
Command | 2 | somedate |
我想从 table 中删除共享相同 ID 的登录和注销之间的所有内容,但保留其他所有内容。 somedate 字段是日期时间。 table 中可能有更多的 logins/logouts,并且会有没有相应注销的登录。我希望它保留在那里,因为注销最终会出现。
我正在考虑使用游标。哪种也是提高性能的最佳方法?最后的 table 可能有几百万行。
删除后 table 应如下所示:
Name | ID |
Login | 2 |
Command | 2 |
Command | 2 |
编辑:删除登录和注销之间的所有内容,包括带有 Login/Logout 的行。
第一次 post 时我想不明白你的问题,编辑更正:
delete from yourTable
where id in (select yt.Id from yourtable yt
inner join yourtable yt2 on yt2.Id = yt.Id and yt2.Name like 'Logout'
where yt.Name like 'Login')
上面应该删除你的table中的所有内容,其中登录有相应的注销
假设每次注销都有相应的登录,您可以试试这个:
DELETE
FROM yourTable
WHERE ID IN
(
SELECT ID
FROM yourTable
WHERE Name LIKE 'Logout'
)
结果将是:
Name | ID |
Login | 2 |
Command | 2 |
Command | 2 |
如果您也想要包含 "Login" 和 "Logout" 的行,您可以这样做:
DELETE
FROM yourTable
WHERE ID IN
(
SELECT ID
FROM yourTable
WHERE Name LIKE 'Logout'
)
AND Name NOT LIKE 'Login'
AND Name NOT LIKE 'Logout'
你会得到这样的结果:
Name | ID |
Login | 1 |
Login | 2 |
Command | 2 |
Logout | 1 |
Command | 2 |
select distinct(id) into @id from your_table where Name = 'Logout'; -- will give you all user id that need to delete
delete from your_table where id in (@id );
有一些模棱两可的情况(如果有没有匹配登录的命令会发生什么?如果登录与注销在同一天,我们是否假设注销是在登录之后?等等)但这应该给你一个起点;
它删除所有非登录或注销记录,其中记录有较早登录,和稍后相同Id的登出记录;
WITH TestData AS (
SELECT 'Login' as Name, 1 AS ID, cast('01/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 1 AS ID, cast('02/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 1 AS ID, cast('03/01/2000' as date) as Date
UNION ALL
SELECT 'Logout' as Name, 1 AS ID, cast('04/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 1 AS ID, cast('05/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 2 AS ID, cast('01/01/2000' as date) as Date
)
DELETE FROM TestData td1
-- Delete any records which are not login or logout
WHERE Name <> 'Login' AND Name <> 'Logout'
-- Where there is an earlier Login
AND EXISTS (SELECT 1 from TestData td2 where td2.Name = 'Login' AND td1.Id = td2.Id AND td2.Date <= td1.Date)
-- and a later logout
AND EXISTS (SELECT 1 from TestData td3 where td3.Name = 'Logout' AND td1.Id = td3.Id AND td3.Date >= td1.Date)
我们做一些测试数据;
IF OBJECT_ID('tempdb..#TestData') IS NOT NULL DROP TABLE #TestData
GO
CREATE TABLE #TestData (Name varchar(7), ID int, Date datetime)
INSERT INTO #TestData (Name, ID, Date)
VALUES
('Login',1,'2016-06-23 12:00:00')
,('Command',1,'2016-06-23 12:05:00')
,('Command',1,'2016-06-23 12:10:00')
,('Login',2,'2016-06-23 12:15:00')
,('Command',1,'2016-06-23 12:20:00')
,('Command',2,'2016-06-23 12:25:00')
,('Logout',1,'2016-06-23 12:30:00')
,('Command',2,'2016-06-23 12:35:00')
我会使用这样的查询。连接查询 returns 特定 ID 在登录和注销日期时间之间的所有行。它不会删除 ID 2 的任何内容,因为该 ID 2 还没有注销。
DELETE TD
FROM #TestData TD
INNER JOIN
(
SELECT a.Name, a.ID, a.Date
FROM #TestData a
LEFT JOIN (
SELECT ID, Date
FROM #TestData
WHERE Name = 'Login'
) lin
ON a.ID = lin.ID
LEFT JOIN (
SELECT ID, Date
FROM #TestData
WHERE Name = 'Logout'
) lout
ON a.ID = lout.ID
WHERE a.Date BETWEEN lin.Date AND lout.Date
) b
ON TD.Date = b.Date
AND TD.ID = b.ID
AND TD.Name = b.Name
这 运行 之后的结果将是
Name ID Date
Login 2 2016-06-23 12:15:00.000
Command 2 2016-06-23 12:25:00.000
Command 2 2016-06-23 12:35:00.000
编辑:更新了我的答案,现在它也删除了 login/logout 命令。
我有以下 table:
Name | ID | date |
Login | 1 | somedate |
Command | 1 | somedate |
Command | 1 | somedate |
Login | 2 | somedate |
Command | 1 | somedate |
Command | 2 | somedate |
Logout | 1 | somedate |
Command | 2 | somedate |
我想从 table 中删除共享相同 ID 的登录和注销之间的所有内容,但保留其他所有内容。 somedate 字段是日期时间。 table 中可能有更多的 logins/logouts,并且会有没有相应注销的登录。我希望它保留在那里,因为注销最终会出现。
我正在考虑使用游标。哪种也是提高性能的最佳方法?最后的 table 可能有几百万行。
删除后 table 应如下所示:
Name | ID |
Login | 2 |
Command | 2 |
Command | 2 |
编辑:删除登录和注销之间的所有内容,包括带有 Login/Logout 的行。
第一次 post 时我想不明白你的问题,编辑更正:
delete from yourTable
where id in (select yt.Id from yourtable yt
inner join yourtable yt2 on yt2.Id = yt.Id and yt2.Name like 'Logout'
where yt.Name like 'Login')
上面应该删除你的table中的所有内容,其中登录有相应的注销
假设每次注销都有相应的登录,您可以试试这个:
DELETE
FROM yourTable
WHERE ID IN
(
SELECT ID
FROM yourTable
WHERE Name LIKE 'Logout'
)
结果将是:
Name | ID |
Login | 2 |
Command | 2 |
Command | 2 |
如果您也想要包含 "Login" 和 "Logout" 的行,您可以这样做:
DELETE
FROM yourTable
WHERE ID IN
(
SELECT ID
FROM yourTable
WHERE Name LIKE 'Logout'
)
AND Name NOT LIKE 'Login'
AND Name NOT LIKE 'Logout'
你会得到这样的结果:
Name | ID |
Login | 1 |
Login | 2 |
Command | 2 |
Logout | 1 |
Command | 2 |
select distinct(id) into @id from your_table where Name = 'Logout'; -- will give you all user id that need to delete
delete from your_table where id in (@id );
有一些模棱两可的情况(如果有没有匹配登录的命令会发生什么?如果登录与注销在同一天,我们是否假设注销是在登录之后?等等)但这应该给你一个起点;
它删除所有非登录或注销记录,其中记录有较早登录,和稍后相同Id的登出记录;
WITH TestData AS (
SELECT 'Login' as Name, 1 AS ID, cast('01/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 1 AS ID, cast('02/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 1 AS ID, cast('03/01/2000' as date) as Date
UNION ALL
SELECT 'Logout' as Name, 1 AS ID, cast('04/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 1 AS ID, cast('05/01/2000' as date) as Date
UNION ALL
SELECT 'Command' as Name, 2 AS ID, cast('01/01/2000' as date) as Date
)
DELETE FROM TestData td1
-- Delete any records which are not login or logout
WHERE Name <> 'Login' AND Name <> 'Logout'
-- Where there is an earlier Login
AND EXISTS (SELECT 1 from TestData td2 where td2.Name = 'Login' AND td1.Id = td2.Id AND td2.Date <= td1.Date)
-- and a later logout
AND EXISTS (SELECT 1 from TestData td3 where td3.Name = 'Logout' AND td1.Id = td3.Id AND td3.Date >= td1.Date)
我们做一些测试数据;
IF OBJECT_ID('tempdb..#TestData') IS NOT NULL DROP TABLE #TestData
GO
CREATE TABLE #TestData (Name varchar(7), ID int, Date datetime)
INSERT INTO #TestData (Name, ID, Date)
VALUES
('Login',1,'2016-06-23 12:00:00')
,('Command',1,'2016-06-23 12:05:00')
,('Command',1,'2016-06-23 12:10:00')
,('Login',2,'2016-06-23 12:15:00')
,('Command',1,'2016-06-23 12:20:00')
,('Command',2,'2016-06-23 12:25:00')
,('Logout',1,'2016-06-23 12:30:00')
,('Command',2,'2016-06-23 12:35:00')
我会使用这样的查询。连接查询 returns 特定 ID 在登录和注销日期时间之间的所有行。它不会删除 ID 2 的任何内容,因为该 ID 2 还没有注销。
DELETE TD
FROM #TestData TD
INNER JOIN
(
SELECT a.Name, a.ID, a.Date
FROM #TestData a
LEFT JOIN (
SELECT ID, Date
FROM #TestData
WHERE Name = 'Login'
) lin
ON a.ID = lin.ID
LEFT JOIN (
SELECT ID, Date
FROM #TestData
WHERE Name = 'Logout'
) lout
ON a.ID = lout.ID
WHERE a.Date BETWEEN lin.Date AND lout.Date
) b
ON TD.Date = b.Date
AND TD.ID = b.ID
AND TD.Name = b.Name
这 运行 之后的结果将是
Name ID Date
Login 2 2016-06-23 12:15:00.000
Command 2 2016-06-23 12:25:00.000
Command 2 2016-06-23 12:35:00.000
编辑:更新了我的答案,现在它也删除了 login/logout 命令。