2016-05-12 58 views
0

我很難找到一個簡單的方法來刪除父ID的所有子記錄。子表也可以有自己的子表,所以我們需要刪除層次結構中的所有記錄。什麼方法最簡單?我可以手動去每個子表,並找到它的子表,然後創建一個腳本,但有太多的表,想知道更簡單的方法。任何幫助感謝!Oracle - 刪除家長的所有子記錄

回答

2

這幾乎是什麼主鍵和外鍵和條款喜歡ON DELETE CASCADE是。如果還不算太晚,您可以在做任何刪除操作之前嘗試添加PK和FK約束;那麼一切都會很容易。

ADDED:基於進一步討論。下面的查詢可用於查找父表的所有後代表。查詢可能在許多方面可能得到改進,但它可能是一個好的起點。

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 
+0

是的,我們已經設置了外鍵。我只需要知道層次結構中的表名和引用的列名。然後,我可以編寫腳本,首先刪除最底層的子表,然後分別刪除其餘的子表。 – user3224907

+1

只需使用級聯刪除,如@mathguy所述。沒有必要寫下自下而上的刪除 – OldProgrammer

+0

我想我明白什麼是OP後...如果FK沒有設置級聯刪除?他/她需要一種列出所有後代的方法來驗證FK是否設置了ON CASCADE DELETE。對於我自己的學習,我正在研究如何完成這一任務 - 無論是使用工具(我確定必須有一些),也可以使用針對ALL_CONSTRAINTS和ALL_CONS_COLUMNS的分層查詢。 – mathguy

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)); 

現在讓我們假設有一個名爲一個子表,相當unoriginally,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' - ah-ha!所以我只是刪除CHILD_TABLE中那些ID_PARENT_TABLE值與我正在刪除的ID_PARENT_TABLE值相匹配的那些行,並且從關係角度來說,所有這些行都與世界是正確的。現在,如果外鍵級聯指定了ON DELETE SET NULL,那麼CHILD_TABLE中與正被刪除的匹配的ID_PARENT_KEY值將被設置爲NULL。此外,如果您沒有指定ANY ON DELETE選項,數據庫將不知道該怎麼做 - 您沒有告訴它刪除匹配的引用,並且您沒有告訴它將匹配的引用設置爲NULL,所以它會拋出它的手(比喻)並拋出一個異常(字面意思),因爲你不能有一個父母不在那裏的子鍵。

請注意,您可以根據需要繼續此操作。比方說,你有另一臺GRAND_CHILD_TABLE它引用CHILD_TABLE:當您從PARENT_TABLE刪除CHILD_TABLE_FK1約束將導致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)); 

現在,和GRAND_CHILD_TABLE_FK1約束將在GRAND_CHILD_TABLE其ID_CHILD_TABLE刪除任何行值匹配從CHILD_TABLE中刪除的值。

祝你好運。