【问题标题】:SQL Server : using information from one table to delete rows in anotherSQL Server:使用一个表中的信息删除另一个表中的行
【发布时间】:2016-10-10 18:04:52
【问题描述】:

我在编写一些 SQL Server 脚本以从两个数据库中删除几行时遇到了一些困难。我已经看到了很多关于这个主题的其他问题,但似乎没有任何东西适用于这种情况。对于这样一个基本问题,我提前道歉,但这是一个不能搞砸的问题。我查询了很多数据,但很少写入表。

我有两个表 rollinfodefects

链接
defects.roll_id = rollinfo.roll_idx

rollinfo 表中有一个名为rollinfo.num_defects 的列。

如果该值大于@MAX_DEFECTS,我想删除它。此外,我想从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”语句。

据记录,这将是大约 200k 行,所以如果有不止一种方法可以做到这一点,我想知道哪种方法更有效。

谢谢,

【问题讨论】:

标签: sql sql-server


【解决方案1】:

由于您需要从 两个 表中删除,因此您需要有两个 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

【讨论】:

  • marc_s,这很有意义,我想我需要删除语句。我试试看。
  • 我建议将其包装在事务中,以防在从 ROLLINFO 删除时删除第一个表后出现问题,否则您可能无法重新创建 id 列表并重新运行删除。
  • @EdwardComeau:绝对 - 更新了我的回复以强调这一事实
【解决方案2】:

你试过了吗?

这可能会也可能不会,具体取决于您的数据库

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;

否则,在同一个批处理中使用两个删除(你说你想写一个脚本,所以一个批处理是正确的做法)。在这个简单的情况下,您不需要事务,因为您已经知道您是唯一与数据库交互的人:

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语句从两个表中删除。
  • 不正确,这取决于数据库实现,有一些支持它的 oracle 和 mysql (innodb) 版本,这就是为什么我提出两种解决方案,如果第一个不起作用(OP 有测试)然后第二个进来。
  • 好吧,这个问题被标记为 [sql-server],它绝对不支持这样的语法。另一方面,我没有意识到其他 DBMS 可能支持它。我今天学了些新东西。谢谢。
猜你喜欢
  • 2021-02-19
  • 1970-01-01
  • 2021-06-07
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-19
相关资源
最近更新 更多