【问题标题】:Delete data with foreign key in SQL Server table删除 SQL Server 表中的外键数据
【发布时间】:2021-06-07 03:21:08
【问题描述】:

我将删除与另一个表(子表)有关系的 SQL Server 表(父表)中的数据。
我尝试了基本的删除查询。但它不起作用(我知道它不会)。

DELETE FROM table WHERE ...

返回以下错误

DELETE 语句与 REFERENCE 约束冲突 ...

我需要保留表的架构。我知道我只需要在查询中添加一些单词,我以前做过,但我就是想不起来。

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    您可以在删除前后禁用和重新启用外键约束:

    alter table MyOtherTable nocheck constraint all
    delete from MyTable
    alter table MyOtherTable check constraint all
    

    【讨论】:

    • 如果您禁用然后重新启用约束,重新启用是否会由于 foreign key 引用损坏而失败?
    • 不,它仅在您将新值写入字段时检查约束 - 当您重新检查时它不会重新扫描整个表。
    • 好吧。这意味着子表中的所有数据都将保留在那里。我即将删除 2k 行,如果我将数据保留在子表中,我认为它会很庞大。我想我会手动完成。无论如何,谢谢大家的回复。你值得 +1 :)
    • 这似乎有点“杂乱无章”,但在我的特殊情况下,我很高兴找到它并且我正在使用它。
    【解决方案2】:

    您需要手动删除子项。两个查询的 <condition> 相同。

    DELETE FROM child
    FROM cTable AS child
    INNER JOIN table AS parent ON child.ParentId = parent.ParentId
    WHERE <condition>;
    
    DELETE FROM parent
    FROM table AS parent
    WHERE <condition>;
    

    【讨论】:

    • 这两个 DELETE 可以组合成我只需要写一次 部分吗?
    • 我不这么认为@ThomasTempelmann。如果您只想编写一次条件,则必须打开级联删除,而不是手动处理每个表。 Alastair Maw 在这里的回答也提到了这个选项。
    【解决方案3】:

    如果您希望自动删除,您需要更改架构,使外键约束为ON DELETE CASCADE

    有关详细信息,请参阅MSDN page on Cascading Referential Integrity Constraints

    ETA(在海报澄清后):如果您无法更新架构,则必须先手动删除受影响的子记录。

    【讨论】:

    • 啊。我错过了在我的帖子中讲述的那部分,我必须在不更改架构的情况下让它工作。有可能吗?
    • 不,使用一些神奇的查询 OPTION 或其他什么东西是不可能的。您需要手动执行删除操作。
    【解决方案4】:

    在这里,您正在为“子”表添加外键

    ALTER TABLE child
    ADD FOREIGN KEY (P_Id)
    REFERENCES parent(P_Id) 
    ON DELETE CASCADE
    ON UPDATE CASCADE;
    

    之后,如果您像这样对“父”表进行 DELETE 查询

    DELETE FROM parent WHERE .....
    

    由于子级通过 DELETE CASCADE 引用了父级,因此“子级”行也将被删除!与“父母”一起。

    【讨论】:

    • 还是不行。这是我的错误ERROR: update or delete on table "question" violates foreign key constraint "answer_question_id_fkey" on table "answer" DETAIL: Key (question_id)=(14) is still referenced from table "answer". SQL state: 23503
    【解决方案5】:

    因此,您需要 DELETE 冲突表中的相关行或更符合逻辑的 UPDATE 他们的 FOREIGN KEY 列以引用父表中的其他 PRIMARY KEY

    另外,您可能想阅读这篇文章Don’t Delete – Just Don’t

    【讨论】:

      【解决方案6】:

      要从具有父子关系的表中删除数据, 首先你必须通过提及join从子表中删除数据,然后简单地从父表中删除数据,示例如下:

      DELETE ChildTable
      FROM ChildTable inner join ChildTable on PParentTable.ID=ChildTable.ParentTableID
      WHERE <WHERE CONDITION> 
      
      
      DELETE  ParentTable
      WHERE <WHERE CONDITION>
      

      【讨论】:

      • 如果您没有级联删除,这是最好的答案。游标的性能很糟糕,删除要删除的约束可能会在其他表中留下孤立的行。
      【解决方案7】:

      有用的脚本,您可以删除数据库所有表中的所有数据, 将 tt 替换为您的数据库名称:

      declare @tablename nvarchar(100)
      declare c1 cursor for
      SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG='tt' AND TABLE_TYPE='BASE TABLE'
      
      open  c1
      fetch next from c1 into @tablename
      
      while @@FETCH_STATUS = 0
          begin
          print @t1
              exec('alter table ' + @tablename + ' nocheck constraint all')
              exec('delete from ' + @tablename)
              exec ('alter table ' + @tablename + ' check constraint all')
              fetch next from c1 into @tablename
          end
      close c1
      DEALLOCATE c1
      

      【讨论】:

        【解决方案8】:

        我使用触发器来删除引用主键的条目。如果不能更改架构,不确定是否可以这样做,但这是 SQLite 中的一个示例:

        CREATE TRIGGER remove_parent
          BEFORE DELETE ON parent
        BEGIN
          DELETE FROM
            child
          WHERE
            child.id = OLD.id;
        END;
        

        这样每次删除父条目时,子条目也会先被删除。

        【讨论】:

          【解决方案9】:

          SET foreign_key_checks = 0; 从您的表中删除; SET foreign_key_checks = 1;

          【讨论】:

          • 这个答案会导致数据库中的数据不一致。仅当您知道自己在做什么时才使用它。
          【解决方案10】:

          在删除 SQL 语句之前和之后设置 FOREIGN_KEY_CHECKS。

          SET FOREIGN_KEY_CHECKS = 0;
          DELETE FROM table WHERE ...
          DELETE FROM table WHERE ...
          DELETE FROM table WHERE ...
          SET FOREIGN_KEY_CHECKS = 1;
          

          来源:https://alvinalexander.com/blog/post/mysql/drop-mysql-tables-in-any-order-foreign-keys

          【讨论】:

          • 问题是关于 SQL Server,而不是 MySQL
          • 这个答案会导致数据库中的数据不一致。仅当您知道自己在做什么时才使用它。如果@Shaunlgs 能解释得更多,那就太好了。
          猜你喜欢
          • 2011-02-19
          • 2018-09-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多