代码之家  ›  专栏  ›  技术社区  ›  RichN

SQL删除孤立项

  •  3
  • RichN  · 技术社区  · 15 年前

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

    简单到 delete from the_table 是否跳过任何包含子记录的行?

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

    4 回复  |  直到 10 年前
        1
  •  6
  •   Community CDub    7 年前

    您可能可以使用扩展的 DELETE 包含错误日志记录的10g语句。

    首次使用 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;
    

    在这种情况下,“屏息”注释将进入 ORA_ERR_TAG$

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

    如果父表很大,而您只想删除一些零散的行,那么您将得到一个 parent_errlog 表,它本质上是您的 parent 桌子如果这样做不好,您将不得不长期这样做:

    1. 直接引用子表(如下所示) Tony's solution ),或,
    2. 在PL/SQL中循环表并捕获任何异常(如下所示 Confusion's Bob's solutions ).
        2
  •  2
  •   Confusion    15 年前

        3
  •  1
  •   Tony Andrews    15 年前

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

    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
  •  1
  •   Bob Jarvis - Слава Україні    15 年前

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

    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;
    

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

    请注意,如果您的桌子很大,这可能需要相当长的时间。