我们通常会在Hibernate中设置好父表与子表的对应关系,并可实现在没有on delete cascade前提下,删除父表时,自动删除子表信息。
但是:如果我们真遇到需要手动处理一些例如“删除某个订单汇总及明细”的需求,而我们不可能去在应用层面增加删除功能。那我们在直接删除汇总时,会遇到“ORA-02292: 违反完整约束条件 - 已找到子记录”。最简单的情形下,我们倒是可以先手动找到明细表,先删掉记录。但是在一个复杂的系统中,我们要一个个去寻找子表,并且可能子表还有子表。。。。那将是个重体力活 X_X! 并且还容易出错。
在这种复杂的环境下,我们只有先将外键全部更改为on delete cascade属性,以便自动级联删除子表记录。(实际上只能重建约束):
下面是我手上系统的一个例子,单独整理了出来,希望可以应急之需:
当然我们会用到外键约束相关的数据字典了。
--可以直接查看到主表的外键与子表,使用动态sql可以批量生成语句:
(需要删除订单汇总表'ECOP_ORDERS' 的某条记录 ,但是其有若干子表,子表还有子表。。。。。。晕吗?哈哈)
select 'alter table '||table_name||' add constraint '||constraint_name||' foreign key (order_id) references ECOP_ORDERS (order_id) on delete cascade;'
from user_constraints where
R_CONSTRAINT_NAME in (select constraint_name from user_constraints where table_name = 'ECOP_ORDERS') ;
select 'alter table '||table_name||' drop constraint '||constraint_name||';'
from user_constraints where
R_CONSTRAINT_NAME in (select constraint_name from user_constraints where table_name = 'ECOP_ORDERS') ;
step1 .先处理直接与ecop_orders关联的子表外键
alter table ECOP_ORDER_INVOICE drop constraint FK_ECOP_ORD_REFERENCE_ECOP_OR7;
alter table ECOP_RETURNEDGOODS drop constraint FK_ECOP_RET_REFERENCE_ECOP_ORD;
alter table ECOP_GIFT_ORDERS drop constraint FK_ECOP_GIF_REFERENCE_ECOP_O23;
alter table ECOP_ORDERS_LEAVE_COMMENTS drop constraint FK_ECOP_ORD_REFERENCE_ECOP_O2;
alter table ECOP_ORDERSTATE drop constraint FK_ECOP_ORD_RELATIONS_ECOP_ORD;
alter table ECOP_ORDER_INVOICE add constraint FK_ECOP_ORD_REFERENCE_ECOP_OR7 foreign key (order_id) references ECOP_ORDERS (order_id) on delete cascade;
alter table ECOP_RETURNEDGOODS add constraint FK_ECOP_RET_REFERENCE_ECOP_ORD foreign key (order_id) references ECOP_ORDERS (order_id) on delete cascade;
alter table ECOP_GIFT_ORDERS add constraint FK_ECOP_GIF_REFERENCE_ECOP_O23 foreign key (order_id) references ECOP_ORDERS (order_id) on delete cascade;
alter table ECOP_ORDERS_LEAVE_COMMENTS add constraint FK_ECOP_ORD_REFERENCE_ECOP_O2 foreign key (order_id) references ECOP_ORDERS (order_id) on delete cascade;
alter table ECOP_ORDERSTATE add constraint FK_ECOP_ORD_RELATIONS_ECOP_ORD foreign key (order_id) references ECOP_ORDERS (order_id) on delete cascade;
step2 .以上ecop_orders子表的子表也需处理。。。当然如果子表很多的话也可以用上面的方式批量生成语句。
--ECOP_RETURNEDGOODS的主键被其子表引用
alter table ECOP_RETURNEDGOODS_DETAILS drop constraint FK_ECOP_RET_REFERENCE_ECOP_RET;
alter table ECOP_RETURNEDGOODS_DETAILS add constraint FK_ECOP_RET_REFERENCE_ECOP_RET foreign key (RETURNEDGOODS_id) references ECOP_RETURNEDGOODS (RETURNEDGOODS_id) on delete cascade;
--ECOP_ORDERS_LEAVE_COMMENTS的主键被其子表引用
alter table ECOP_ORDER_REPLY drop constraint FK_ECOP_ORD_REFERENCE_ECOP_O3;
alter table ECOP_ORDER_REPLY add constraint FK_ECOP_ORD_REFERENCE_ECOP_O3 foreign key (LEAVE_COMMENTS_ID) references ECOP_ORDERS_LEAVE_COMMENTS (LEAVE_COMMENTS_ID) on delete cascade;
--ECOP_ORDERSTATE的主键被其子表引用
alter table ECOP_ORDERSTATE_DETAIL drop constraint FK_ECOP_ORD_REFERENCE_ECOP_O58;
alter table ECOP_ORDERSTATE_DETAIL add constraint FK_ECOP_ORD_REFERENCE_ECOP_O58 foreign key (ORDER_STATE_ID) references ECOP_ORDERSTATE (ORDER_STATE_ID) on delete cascade;
step3 .最后就可顺利删除ecop_orders记录
delete from ecop_orders ... 搞定!
因此,我们最好还是在设计阶段,在外键上加上on delete cascade属性。特别是我们预计到,将来会有删除父表记录的需求。
改进版:
SELECT 'alter table '||UC.TABLE_NAME||' add constraint '||UC.CONSTRAINT_NAME||' foreign key '||UCC.COLUMN_NAME||' references IWS_EEG_GEB ('||PT.COLUMN_NAME||') on delete cascade;'
FROM USER_CONSTRAINTS UC,USER_CONS_COLUMNS UCC,
(SELECT b.CONSTRAINT_NAME,b.COLUMN_NAME FROM USER_CONSTRAINTS a,USER_CONS_COLUMNS b WHERE a.CONSTRAINT_NAME=b.CONSTRAINT_NAME and a.TABLE_NAME = 'IWS_EEG_GEB') PT
WHERE uc.R_CONSTRAINT_NAME=PT.CONSTRAINT_NAME
AND UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME
select 'alter table '||uc.table_name||' drop constraint '||uc.constraint_name||';'
FROM USER_CONSTRAINTS UC,USER_CONS_COLUMNS UCC WHERE
uc.R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'IWS_EEG_GEB')
AND UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME