【问题标题】:Deleting 'equivalent' data from two tables从两个表中删除“等效”数据
【发布时间】:2013-03-06 11:54:55
【问题描述】:

我需要在 SQL Server 2012 过程中执行以下伪逻辑,基于表变量和这样声明的表:

DECLARE @tmp TABLE
    (
    ID int IDENTITY(1,1),
    UserID int NOT NULL,
    SgsID int NOT NULL
    )

CREATE TABLE #Table1
    (
    ID int IDENTITY(1,1),
    UserID int NOT NULL,
    SgsID int NOT NULL
    )
  1. 对于表变量@tmp中的每一行数据
  2. 从Table1 中删除行,其中UserID/SgsID 组合匹配UserID/SgsID in Table1
  3. 从@tmp中删除那些已经从Table1中删除的UserID/SgsID组合

我一直在研究不同的方法,例如使用OUTPUT INTO 和INTERSECT,但无法编写跨两个表删除的查询(实际上我认为这根本不可能)。

我已经通过使用以下代码实现了上述步骤,但是,我想知道是否有任何 T-SQL 专业人士能够提出更简洁/有效的方法?

见SQLFiddle for online version

CREATE TABLE #Table1
    (
    ID int IDENTITY(1,1),
    UserID int NOT NULL,
    SgsID int NOT NULL
    )

INSERT INTO #Table1 (UserID, SgsID) VALUES (5, 99)
INSERT INTO #Table1 (UserID, SgsID) VALUES (10, 89)
INSERT INTO #Table1 (UserID, SgsID) VALUES (150, 79)
INSERT INTO #Table1 (UserID, SgsID) VALUES (200, 69)
INSERT INTO #Table1 (UserID, SgsID) VALUES (250, 59)
SELECT * FROM #Table1 

DECLARE @tmp TABLE
    (
    ID int IDENTITY(1,1),
    UserID int NOT NULL,
    SgsID int NOT NULL
    )

INSERT INTO @tmp (UserID, SgsID) VALUES (150, 79)
INSERT INTO @tmp (UserID, SgsID) VALUES (200, 69)
INSERT INTO @tmp (UserID, SgsID) VALUES (250, 59)
INSERT INTO @tmp (UserID, SgsID) VALUES (999, 49)
SELECT * FROM @tmp

DECLARE @tbl_commonRows TABLE (UserID int, SgsID int)
INSERT INTO @tbl_commonRows 
    (
    UserID,
    SgsID
    ) 
SELECT 
    UserID,
    SgsID 
FROM
    #Table1
INTERSECT 
SELECT
    UserID,
    SgsID
FROM
    @tmp 

DELETE FROM 
    #Table1 
WHERE 
    (ID IN (
        SELECT 
            ID 
        FROM 
            #Table1 t1 INNER JOIN
            @tbl_commonRows c ON c.UserID = t1.UserID AND c.SgsID = t1.SgsID))

DELETE FROM
    @tmp
WHERE
    (ID IN (
        SELECT
            ID
        FROM
            @tmp t2 INNER JOIN
            @tbl_commonrows c ON c.UserID = t2.UserID AND c.SgsID = t2.SgsID))

SELECT * FROM #Table1 
SELECT * FROM @tmp
DROP TABLE #Table1

【问题讨论】:

    标签: sql-server tsql sql-server-2012


    【解决方案1】:

    解决办法:

    DECLARE @tmp_ids TABLE (
        id1 INT,
        id2 INT
    )
    
    INSERT INTO @tmp_ids (id1, id2)
    SELECT 
        t1.id,
        t2.id
    FROM Table1 t1
    INNER JOIN tmp t2
        on (t1.UserID = t2.UserID AND t1.SgsID = t2.SgsID)
    
    DELETE FROM Table1
    WHERE id IN (SELECT id1 FROM @tmp_ids)
    
    DELETE FROM tmp
    WHERE id IN (SELECT id2 FROM @tmp_ids)
    

    记住 - 我创建了物理表 tmp 和 Table1

    【讨论】:

    • 它无法正常工作。例如@tmp表中有记录(250, 100)和(250, 59),#Table1中有(250, 59)。两条记录都将从@tmp 中删除,尽管#Table1 中只有(250, 29) 匹配并且应该从@tmp 中删除。
    • @Sergio 如果你用我建议的场景实际测试过它,你会发现它不适用于那种特殊情况......
    • @IvanG 哈哈,刚刚意识到它在 sqlfiddle 中工作不正确。但是 ssms 一切都很好。猜猜这是一个 sqlfiddle 错误
    • @Sergio 这不可能是 SQL Fiddle 错误,因为该站点下面有 SQL Server,只是通过接口传递数据。无论如何,我在 SSMS 中测试了您的解决方案,而不是在 SQL Fiddle 上,该解决方案不适用于我所描述的情况,希望 OP 会针对这种情况对其进行测试。
    • @Sergio 的查询没问题,我误解了他的部分查询,没关系,抱歉……
    【解决方案2】:

    您可以利用 OUTPUT 命令可以使用超过 INSERTED 和 DELETED 列进行删除(但不是插入,遗憾的是)这一事实:

        DECLARE @output TABLE (id int) 
    
        DELETE FROM tbl
        OUTPUT tmp.ID INTO @output(id)
        FROM #Table1 tbl
        JOIN @tmp tmp 
            ON tbl.UserID = tmp.UserID 
            AND tbl.SgsID = tmp.SgsID
    
        DELETE FROM tmp
        FROM @tmp tmp
        JOIN @Output outp ON tmp.id = outp.id   
    

    【讨论】:

    • 当我遇到你的答案时,我希望没有人发过这个。 :) 不错。
    • 不知道那个,谢谢。但是,两个表中的 ID 列可能不同,因为在 UserID/sgsID 中,表中的对应 ID 可能不同。请问您的代码在这种情况下仍然相关吗?
    • @EvilDr 是的;这实际上是想要输出 tmp.ID 的一个原因,这样您就知道在删除 tmp 时您将返回到相应的行。
    【解决方案3】:

    您是否考虑过为此使用 MERGE?可能是另一种选择,语法很好且易于理解。

    MERGE (Transact-SQL)

    【讨论】:

    • 您能否发布一个示例来说明如何使用它?我认为因为 MERGE 基于源表对目标表进行操作,所以这里不适合,因为我们同时对源表和目标表进行操作...?
    • 您可以通过使用输出子句修改源表来扩展合并:stackoverflow.com/questions/7331725/…
    • 今天早上玩了 MERGE - 我非常喜欢它。多么了不起的补充。与 OUTPUT 合并非常好:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    相关资源
    最近更新 更多