SQL Server:使用一个表中的信息删除另一个表中的行

SQL Server:使用一个表中的信息删除另一个表中的行,sql,sql-server,Sql,Sql Server,我在编写SQL Server脚本以从两个数据库中删除几行时遇到了一些困难。我已经看到了很多关于这个主题的其他问题,但是对于这个场景来说似乎没有什么是有效的。对于这样一个基本的问题,我提前表示歉意,但这是一个a不能搞砸的问题。我查询了很多数据,但很少对表进行写操作 我有两个表rollinfo和defects,它们通过 defects.roll_id = rollinfo.roll_idx rollinfo表中有一列名为rollinfo.num\u defects 如果该值大于@MAX\u DEF

我在编写SQL Server脚本以从两个数据库中删除几行时遇到了一些困难。我已经看到了很多关于这个主题的其他问题,但是对于这个场景来说似乎没有什么是有效的。对于这样一个基本的问题,我提前表示歉意,但这是一个a不能搞砸的问题。我查询了很多数据,但很少对表进行写操作

我有两个表
rollinfo
defects
,它们通过

defects.roll_id = rollinfo.roll_idx
rollinfo
表中有一列名为
rollinfo.num\u defects

如果该值大于
@MAX\u DEFECTS
,我想将其删除。此外,我想从
缺陷
表中删除任何相应的行

选择此信息很容易:

SELECT
    D.ROLL_ID,
    R.ROLL_IDX
FROM 
    VISION17SLITTER.DBO.ROLLINFO R
INNER JOIN 
    VISION17SLITTER.DBO.DEFECTS D ON D.ROLL_ID = R.ROLL_IDX
WHERE
    R.NUM_DEFECTS > @MAX_DEFECTS
但是,我不确定是否可以通过将select语句更改为delete来同时删除两个表中的行,或者是否需要执行某种类型的“where exists”语句

为了记录在案,这将是大约20万行,所以如果有不止一种方法可以做到这一点,我想知道哪一种更有效

谢谢

丹,你试过这个吗

这可能有效,也可能无效,具体取决于您的数据库

DELETE D, R
FROM
    VISION17SLITTER.DBO.ROLLINFO R
    INNER JOIN
    VISION17SLITTER.DBO.DEFECTS D
    ON D.ROLL_ID = R.ROLL_IDX
WHERE R.NUM_DEFECTS > @MAX_DEFECTS;
否则,在同一批中使用两次删除(您说要编写脚本,所以批处理是正确的做法)。在这种简单的情况下,您不需要事务,因为您已经知道您是唯一与DB交互的人:

DELETE D
FROM
    VISION17SLITTER.DBO.ROLLINFO R
    INNER JOIN
    VISION17SLITTER.DBO.DEFECTS D
    ON D.ROLL_ID = R.ROLL_IDX
WHERE R.NUM_DEFECTS > @MAX_DEFECTS;

DELETE R
FROM
    VISION17SLITTER.DBO.ROLLINFO R
WHERE R.NUM_DEFECTS > @MAX_DEFECTS;

GO

如果您不希望脚本在应用程序静止时手动启动,则必须考虑并发性,并且实际事务是有序的:

BEGIN TRANSACTION

  DELETE D
  FROM
    VISION17SLITTER.DBO.ROLLINFO R
    INNER JOIN
    VISION17SLITTER.DBO.DEFECTS D
    ON D.ROLL_ID = R.ROLL_IDX
  WHERE R.NUM_DEFECTS > @MAX_DEFECTS;

  DELETE R
  FROM
    VISION17SLITTER.DBO.ROLLINFO R
  WHERE R.NUM_DEFECTS > @MAX_DEFECTS;

COMMIT;

由于需要从两个表中删除,因此需要有两个
delete
语句,因此我认为最好的方法是将需要删除的ID写入一个临时表中,然后用它来驱动两个
delete
语句:

-- create the temp table - you didn't mention what the datatype for these two columns is - adapt as needed
CREATE TABLE #IDsToBeDeleted (ID INT NOT NULL)  

-- select those ID's you want to delete into the temp table
INSERT INTO #IDsToBeDeleted (ID)  
    SELECT
        D.ROLL_ID
    FROM 
        VISION17SLITTER.DBO.ROLLINFO R
    INNER JOIN 
        VISION17SLITTER.DBO.DEFECTS D ON D.ROLL_ID = R.ROLL_IDX
    WHERE
        R.NUM_DEFECTS > @MAX_DEFECTS

-- based on the temp table, now delete from the two tables  
-- again, from your question it isn't entirely clear which 
-- is the "parent" table, and which the "child" table - so you
-- might need to change the order of deleting those rows to
-- match your situation

BEGIN TRANSACTION
BEGIN TRY    
    DELETE FROM VISION17SLITTER.DBO.DEFECTS 
    WHERE ROLL_ID IN (SELECT ID FROM #IDsToBeDeleted)    

    DELETE FROM VISION17SLITTER.DBO.ROLLINFO 
    WHERE ROLL_IDX IN (SELECT ID FROM #IDsToBeDeleted)

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    -- report and log the error
    ROLLBACK TRANSACTION
END CATCH

Use可以使用
级联删除
外键约束,因此您只需删除一次缺陷,它们将从相关表中删除。可能重复marc_s,这很有意义,我想我需要删除语句。我会尝试一下。我建议在事务中包装,以防在从ROLLINFO删除时删除第一个表后出现问题,否则,您可能无法重新创建id列表并重新运行删除。@EdwardComeau:Absolute-更新了我的响应,以突出显示您不能用一个
delete
语句从两个表中删除的事实。不正确,这取决于数据库实现,有些oracle和mysql(innodb)版本支持它,这就是为什么我提出这两种解决方案,如果第一种方案不起作用(OP必须测试),那么第二种方案就出现了。好吧,问题被标记为[sql server],它肯定不支持这种语法。另一方面,我没有意识到其他数据库管理系统可能支持它。今天我学到了一些新东西。谢谢