【问题标题】:SQL delete orphanSQL删除孤儿
【发布时间】:2011-01-02 20:01:22
【问题描述】:

假设所有外键都有适当的约束,是否有一个简单的 SQL 语句来删除数据库中任何地方都没有引用的行?

像delete from the_table 这样简单地跳过任何带有子记录的行?

我试图避免手动循环遍历表格或添加类似where the_SK not in (a,b,c,d) 的内容。

【问题讨论】:

    标签: sql oracle delete-row


    【解决方案1】:

    您或许可以在 10g 中使用扩展的 DELETE 语句,其中包括错误日志记录。

    首先使用DBMS_ERRLOG创建一个日志表(它只是原始表的一个副本,带有一些额外的前缀列:ORA_ERR_MESG$, ..., ORA_ERR_TAG$)

    execute dbms_errlog.create_error_log('parent', 'parent_errlog');
    

    现在,您可以使用 delete 语句的 LOG ERRORS 子句来捕获所有具有现有完整性约束的行:

    delete from parent
       log errors into parent_errlog ('holding-breath')
       reject limit unlimited;
    

    在这种情况下,“holding-breath”注释将进入ORA_ERR_TAG$ 列。

    您可以阅读完整的文档here。

    如果父表很大并且您只想删除一些杂散行,您最终会得到一个parent_errlog 表,它本质上是您的parent 表的副本。如果这不行,您将不得不做很长的路要走:

    1. 直接引用子表(在Tony's solution之后),或者,
    2. 在 PL/SQL 中循环遍历表并捕获任何异常(在 Confusion's 和 Bob's solutions 之后)。

    【讨论】:

    • 很好,我不知道这个错误记录。这样我既不需要指定孩子也不需要遍历行,但我认为你应该添加“拒绝限制无限”(或任何数字)。事实上,删除仍然失败。
    • 很好发现 - 添加到我的答案中
    【解决方案2】:

    最简单的方法可能是编写一个应用程序或存储过程,尝试逐一删除表中的行,并简单地忽略由于外键约束而导致的失败。之后,应删除所有不受外键约束的行。根据所需/可能的性能,这可能是一种选择。

    【讨论】:

      【解决方案3】:

      没有。显然你可以这样做(但我知道你宁愿不这样做):

      delete parent
      where  not exists (select null from child1 where child1.parent_id = parent.parent_id)
      and    not exists (select null from child2 where child2.parent_id = parent.parent_id)
      ...
      and    not exists (select null from childn where childn.parent_id = parent.parent_id);
      

      【讨论】:

        【解决方案4】:

        一种方法是编写如下内容:

        eForeign_key_violation EXCEPTION;
        PRAGMA EXCEPTION_INIT(eForeign_key_violation, -2292);
        
        FOR aRow IN (SELECT primary_key_field FROM A_TABLE) LOOP
          BEGIN
            DELETE FROM A_TABLE A
            WHERE A.PRIMARY_KEY_FIELD = aRow.PRIMARY_KEY_FIELD;
          EXCEPTION
            WHEN eForeign_key_violation THEN
              NULL;  -- ignore the error
          END;
        END LOOP;
        

        如果存在子行,DELETE 将失败,不会删除任何行,您可以继续下一个键。

        请注意,如果您的表很大,这可能需要很长时间。

        【讨论】:

          猜你喜欢
          • 2012-10-22
          • 2012-02-07
          • 2010-09-23
          • 2014-10-07
          • 2013-06-05
          • 2011-02-09
          • 2012-08-16
          • 1970-01-01
          相关资源
          最近更新 更多