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