Oracle - 删除父项的所有子记录

时间:2016-05-12 19:43:58

标签: sql oracle

我很难找到一种简单的方法来删除父ID的所有子记录。子表也可以有自己的子表,因此我们需要删除层次结构中的所有记录。最简单的方法是什么?我可以手动转到每个子表并找到它的子表,然后创建一个脚本,但是有太多的表,想知道一个更简单的方法。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:2)

这几乎是ON DELETE CASCADE等主键和外键和子句的用途。如果还不晚,你可以尝试在删除之前添加PK和FK约束;一切都会变得简单。

已添加:基于进一步的讨论。下面的查询可用于查找父表的所有后代表。查询可能会在很多方面得到改进,但它可能是一个很好的起点。

with f as (
        select constraint_name, table_name, r_constraint_name
        from   user_constraints
        where  constraint_type = 'R'
     ),
     p as (
        select constraint_name, table_name
        from   user_constraints
        where  constraint_type = 'P'
     ),
     j (child_table, f_key, parent_table, p_key) as (
        select f.table_name, f.constraint_name, p.table_name, f.r_constraint_name
        from   p join f on p.constraint_name = f.r_constraint_name
        union all
        select 'EMPLOYEES', (select constraint_name from p 
                                where table_name = 'EMPLOYEES'), null, null from dual
     )
select level as lvl, j.*
from j
start with parent_table is null
connect by nocycle parent_table = prior child_table
order by lvl, parent_table, child_table;

在这种情况下,“父”表是EMPLOYEES,名称在同一行显示两次。如果需要,可以将其设置为绑定变量。我使用了EMPLOYEES(注意:它必须是全部大写的,因为这是字符串值存储在系统表中的方式)因为我在标准HR模式上运行它;输出:

  LVL CHILD_TABLE       F_KEY                PARENT_TABLE      P_KEY
----- ----------------- -------------------- ----------------- -----------------
    1 EMPLOYEES         EMP_EMP_ID_PK
    2 DEPARTMENTS       DEPT_MGR_FK          EMPLOYEES         EMP_EMP_ID_PK
    2 JOB_HISTORY       JHIST_EMP_FK         EMPLOYEES         EMP_EMP_ID_PK
    3 JOB_HISTORY       JHIST_DEPT_FK        DEPARTMENTS       DEPT_ID_PK

答案 1 :(得分:2)

让我们考虑一个实际的例子。假设您有一个名为PARENT_TABLE的表:

CREATE TABLE PARENT_TABLE
  (ID_PARENT_TABLE  NUMBER
     CONSTRAINT PK_PARENT_TABLE
       PRIMARY KEY
         USING INDEX,
   PARENT_ATTR_1    NUMBER,
   PARENT_ATTR_2    VARCHAR2(100),
   BLAH_BLAH_BLAH   VARCHAR2(50));

现在让我们假设有一个名为CHILD_TABLE非常原始的子表:

CREATE TABLE CHILD_TABLE
  (ID_CHILD_TABLE     NUMBER
     CONSTRAINT PK_CHILD_TABLE
       PRIMARY KEY
         USING INDEX,
   ID_PARENT_TABLE    NUMBER
     CONSTRAINT CHILD_TABLE_FK1
       REFERENCES PARENT_TABLE(ID_PARENT_TABLE)
         ON DELETE CASCADE,
   CHILD_ATTR_1       NUMBER,
   WHATEVER           VARCHAR2(100));

外键约束CHILD_TABLE_FK1在这里真正起作用。当你从PARENT_TABLE中删除时,数据库注意到CHILD_TABLE_FK1引用了PARENT_TABLE(ID_PARENT_TABLE),所以数据库说,“嗯...我正在删除PARENT_TABLE中的一行,其中ID_PARENT_TABLE值为(让我们说)10 - 我想知道是否有是由这个CHILD_TABLE_FK1约束命名的表中的任何行,它也恰好具有ID_PARENT_TABLE值10.嗯,由Jupiter,有!哇 - 我应该怎么做?好吧,约束说'ON DELETE CASCADE' - 啊哈!所以我只是删除CHILD_TABLE中那些ID_PARENT_TABLE值与我正在删除的值相匹配的行,从关系来讲,所有这些行都是正确的“。现在,如果外键级联已指定ON DELETE SET NULL,则CHILD_TABLE中与正被删除的ID_PARENT_KEY值之间的值将设置为NULL。此外,如果您没有指定任何ON DELETE选项,则数据库将不知道该怎么做 - 您没有告诉它删除匹配的引用,并且您没有告诉它设置匹配的引用为NULL,所以它会抛出它的手(比喻)并抛出一个异常(字面意思),因为你不能拥有父元素不再存在的子键。

请注意,您可以根据需要继续此操作。假设您有另一个引用GRAND_CHILD_TABLE的表CHILD_TABLE

CREATE TABLE GRAND_CHILD_TABLE
  (ID_GRAND_CHILD_TABLE  NUMBER
     CONSTRAINT PK_GRAND_CHILD_TABLE
       PRIMARY KEY
         USING INDEX,
   ID_CHILD_TABLE        NUMBER
     CONSTRAINT GRAND_CHILD_TABLE_FK1
       REFERENCES CHILD_TABLE(ID_CHILD_TABLE)
         ON DELETE CASCADE,
   what_EVER             VARCHAR2(25));

现在当您从PARENT_TABLE中删除时,CHILD_TABLE_FK1约束将导致CHILD_TABLE中的任何匹配行被删除,GRAND_CHILD_TABLE_FK1约束将删除GRAND_CHILD_TABLE中ID_CHILD_TABLE值与从CHILD_TABLE中删除的值匹配的任何行。

祝你好运。