【问题标题】:How to delete all dependent rows如何删除所有依赖行
【发布时间】:2015-02-04 09:32:28
【问题描述】:

我有一个表 A,它有主键列 a,它是 B 表的外键(表 B 有主键 b和列a)。表B还有一个主键b,它是C表的外键等等。

现在,如果我想从表 A 中删除一行,那么它不会允许我,因为它的依赖表 B 和表 B 依赖于表 C。所以我必须先从 C 中删除一行,然后是 B,最后是手动删除 A

所以谁能告诉我是否有任何方法可以直接删除,而无需转到每个表并检查它是否有任何依赖关系然后删除

【问题讨论】:

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


【解决方案1】:

如果不允许修改表,可以查看EXISTS 运算符。
仅当EXISTS 中的查询返回至少 1 个结果时,它才允许您从表中删除行。您可以使用它来检查依赖关系。

你可以写3个查询:

DELETE C c
WHERE EXISTS (SELECT 1
              FROM B b
              WHERE c.b = b.b
              AND EXISTS (SELECT 1
                          FROM A a
                          WHERE a.a = b.a
                          AND ... ));
DELETE B b
WHERE EXISTS (SELECT 1
              FROM A a
              WHERE a.a = b.a
              AND ...);

DELETE A a
WHERE ...

第一个将处理 C 中的记录,该记录引用 B 中的记录,该记录引用您要删除的 A 中的记录。
然后您可以从B 中删除记录,因为C 中没有更多的依赖项。
最后,您可以使用相同的逻辑从A 中删除记录。

【讨论】:

    【解决方案2】:

    您可以使用 Cascade Cascading Referential Integrity Constraints

    更新: 您应该从表 B 中启用表 A (PK) 的级联参照完整性约束,其中 A 的 ID 是外键,类似地从表 C 中启用表 B 的 PK,其中 B 的 ID 是外键

    MSDN LIBRARY

    CODE PROJECT ARTICALE

    非常好的文章BLOG.SQL AUTHORITY

    【讨论】:

    • 感谢您提供有用的链接,+1
    • @SpringLearner :我已经更新了我的答案并添加了快照,它可能会对您有所帮助
    【解决方案3】:

    您正在寻找的术语是“级联” - 您需要级联删除。您可以启用它们,如下所述:How do I use cascade delete with SQL Server?

    【讨论】:

    • 感谢您的回答,但我不知道哪些表与 c 链接,然后是其他表。所以根据链接的问题,我该如何继续?
    • 感谢您的链接,+1
    【解决方案4】:

    您可以使用级联参照完整性,请参阅question。但是,请注意,过多的级联 RI,您可能会在不知不觉中造成很多损害!

    【讨论】:

      【解决方案5】:

      正如其他人已经指出的那样,cascade delete 是您正在寻找的。在其中一个 cmets 中,您提到您不知道依赖关系。这是一个列出依赖项的脚本

      SELECT Db_name()                                   referencing_database_name, 
             Object_name (referencing_id)                referencing_entity_name, 
             Isnull(referenced_schema_name, 'dbo')       referenced_schema_name, 
             referenced_entity_name, 
             ao.type_desc                                referenced_entity_type, 
             Isnull(referenced_database_name, Db_name()) referenced_database_name 
      FROM   sys.sql_expression_dependencies sed 
             JOIN sys.all_objects ao 
               ON sed.referenced_entity_name = ao.name  
      WHERE ao.type_desc = 'USER_TABLE' 
      

      【讨论】:

      • 谢谢,它给了我所有的表。是否可以只从表 A 中获取依赖关系?
      • WHERE 子句更改为按referenced_entity_name 过滤
      • 我确实喜欢这个 WHERE referenced_entity_name = 'A' ,但它没有给我任何列
      • 它只会给你引用和引用的表。不是列
      • 现在它说 Object 没有引用任何对象,也没有对象引用它。
      【解决方案6】:

      自动删除取决于您如何定义表之间的关系。

      如果您在尝试删除主表中的行时遇到错误,那是因为您没有在删除关系中指定特殊操作。

      我的意思是更改 FK 中的 ON DELETEON UPDATE 选项。这允许指定当您删除或更新主表中的行时子行会发生什么。例如,ON DELETE CASCADE 选项将完全符合您的要求。

      例如:

      CREATE TABLE Sales.TempSalesReason (
        TempID int NOT NULL, Name nvarchar(50
      ), 
      CONSTRAINT PK_TempSales PRIMARY KEY NONCLUSTERED (TempID), 
      CONSTRAINT FK_TempSales_SalesReason FOREIGN KEY (TempID) 
        REFERENCES Sales.SalesReason (SalesReasonID) 
        ON DELETE CASCADE
        ON UPDATE CASCADE
      )
      

      会这样,当您删除或修改主表中的一行时,该行也会在子表中被修改或删除。

      相关文档:

      【讨论】:

      • 感谢您的回答,我了解ON DELETE CASCADE 的目的。ON UPDATE CASCADE 的目的是什么,是用来更新列数据类型的吗?
      • ON UPDATE CASCADE 表示如果修改父行中的键,则相关子行上的键将自动更新以匹配新的父键
      【解决方案7】:

      有一个存储过程 'sp_fkeys' 将提供特定表的所有外键

      exec sp_fkeys 'My_Table'
      

      因此您可以将输出保存到临时表中,然后在游标中删除所有具有任何依赖关系的行。如果任何嵌套表也有依赖关系,你会做同样的事情,但嵌套表(递归)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-20
        • 2021-06-12
        • 1970-01-01
        • 2019-01-22
        • 1970-01-01
        • 2018-06-18
        • 2020-05-29
        • 2016-11-23
        相关资源
        最近更新 更多