从表中删除共享相同 ID 的所有行

Posted

技术标签:

【中文标题】从表中删除共享相同 ID 的所有行【英文标题】:Deleting all rows from table that share the same ID 【发布时间】:2016-06-23 09:29:35 【问题描述】:

我有下表:

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 |

我想从表中删除登录和注销之间共享相同 ID 的所有内容,但保留其他所有内容。 somedate 字段是日期时间。表中可能有更多登录/注销,并且会有没有相应注销的登录。我希望它保留在那里,因为注销最终会出现。

我正在考虑使用光标。哪个也是最好的性能方法?最终表格可能有几百万行。

删除后的表格应该是这样的:

Name    |  ID  |  
Login   |  2   |
Command |  2   |
Command |  2   |

编辑:删除登录和注销之间的所有内容,包括登录/注销的行。

【问题讨论】:

像 chris 更新一样,尝试获取所有具有“注销”条目的 ID。直接删除。 你的结果让我很困惑,你想完全删除ID 1,因为它既有登录又有注销的外观? @RichBenner 是的,确切地说,包括登录和注销。 好的,您的措辞令人困惑“我想从表中删除登录和注销之间的所有内容”。之间不包括登录和注销命令,我会在几分钟内更新我的答案。 @RichBenner 很抱歉造成混乱。 【参考方案1】:

假设每次注销都有相应的登录名,您可以试试这个:

DELETE
FROM yourTable
WHERE ID IN
(
    SELECT ID
    FROM yourTable
    WHERE Name LIKE 'Logout'
)

结果是:

Name    |  ID  |
Login   |  2   |
Command |  2   |
Command |  2   |

如果您也想拥有带有“登录”和“注销”的行,您可以这样做:

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   |

【讨论】:

在此示例中,ID 似乎不是主键,因此这将删除所有记录,包括登录和注销,我认为这不是 OP 所要求的 @Milney 看看他的预期结果。他也想删除登录和注销。【参考方案2】:

有一些模棱两可的情况(如果有没有匹配登录的命令会发生什么?如果登录与注销是在同一天,我们是否假设注销是在登录之后?等等)但这应该给你一个起点;

它删除所有不是登录或注销记录的记录,其中记录具有较早登录和较晚注销记录同一个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)

【讨论】:

【参考方案3】:

让我们做一些测试数据;

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')

我会使用这样的查询。连接查询返回登录和注销日期时间之间的特定 ID 的所有行。它不会删除 ID 2 的任何内容,因为该 ID 还没有注销。

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

编辑:更新了我的答案,现在它也删除了登录/注销命令。

【讨论】:

完美运行! 欢迎对任何对您有帮助的答案投票。如果解决了特定问题,请标记为已接受。【参考方案4】:

我错过了在我的第一篇文章中理解你的问题,编辑更正:

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')

以上内容应该从您的表中删除登录名具有相应注销的所有内容

【讨论】:

我认为他只是没有很好地解释自己。 在此示例中,ID 似乎不是主键,因此这将删除所有记录,包括登录和注销,我认为这不是 OP 所要求的 @Milney 在我看来,OP 只想保留登录但没有注销的记录。这将删除具有相同 Id 的所有记录,没有主键会是一个问题,但 Id 可能来自唯一的连接。【参考方案5】:
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 似乎不是主键,因此这将删除所有记录,包括登录和注销,我认为这不是 OP 所要求的 感谢您指出这一点。 OP 提到了登录和注销之间的所有内容,但在预期的结果中,OP 不想同时获得这两个条目。认为他需要编辑帖子:)

以上是关于从表中删除共享相同 ID 的所有行的主要内容,如果未能解决你的问题,请参考以下文章

想要使用其他公司代码表从表中删除行

SqlDataAdapter 不会从表中删除行

sql 使用Mysql中的ID从表中删除许多行

MySQL - 选择共享相同 ID 的所有行,每行包含等于 null 的列

从表中选择行,其中具有相同 id 的另一个表中的行在另一列中具有特定值

从表中删除 WHERE NOT MAX