级联删除

Oracle在外键的删除上有NO ACTION(类似RESTRICT)、CASCADE和SET NULL三种行为。

下面以学生-班级为例说明不同情况下的外键删除,学生属于班级,班级的主键是学生的外键。

-- 班级表  



1


2


3


4


5


6




​CRATE ​​​​TABLE​​​​TB_CLASS ​



​( ​



​ ​​​​ID NUMBER ​​​​NOT​​​​NULL​​​​, ​​​​--班级主键 ​



​ ​​​​NAME​​​​VARCHAR2(50), ​​​​--班级名称 ​



​ ​​​​CONSTRAINT​​​​PK_TB_CLASS ​​​​PRIMARY​​​​KEY​​​​(ID) ​



​); ​






-- 学生表 



1


2


3


4


5


6


7


8


9


10


11


12


13




​CREATE​​​​TABLE​​​​TB_STUDENT ​



​( ​



​ ​​​​ID  NUMBER ​​​​NOT​​​​NULL​​​​, ​​​​--学生主键 ​



​ ​​​​NAME​​​​VARCHAR2(50),  ​​​​--学生姓名 ​



​ ​​​​CLASS_ID NUMBER,   ​​​​--学生所属班级,外键 ​



​ ​​ 



​ ​​​​--主键约束 ​



​ ​​​​CONSTRAINT​​​​PK_TB_STUDENT ​​​​PRIMARY​​​​KEY​​​​(ID), ​



​ ​​ 



​ ​​​​--外键约束 ​



​ ​​​​--设置级联删除为NO ACTION ​



​ ​​​​CONSTRAINT​​​​FK_TB_STUDENT_CLASS_ID ​​​​FOREIGN​​​​KEY​​​​(CLASS_ID) ​​​​REFERENCES​​​​TB_CLASS (ID) ​



​); ​






-- 添加班级数据  


1


2


3




​INSERT​​​​INTO​​​​TB_CLASS (ID, ​​​​NAME​​​​) ​​​​VALUES​​​​(1, ​​​​'一班'​​​​); ​



​INSERT​​​​INTO​​​​TB_CLASS (ID, ​​​​NAME​​​​) ​​​​VALUES​​​​(2, ​​​​'二班'​​​​); ​



​INSERT​​​​INTO​​​​TB_CLASS (ID, ​​​​NAME​​​​) ​​​​VALUES​​​​(3, ​​​​'三班'​​​​); ​






-- 添加学生数据 


1


2


3


4


5


6


7


8


9




​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(1, ​​​​'小明'​​​​, 1); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(2, ​​​​'小刚'​​​​, 1); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(3, ​​​​'小王'​​​​, 1); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(4, ​​​​'二明'​​​​, 2); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(5, ​​​​'二刚'​​​​, 2); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(6, ​​​​'二王'​​​​, 2); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(7, ​​​​'大明'​​​​, 3); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(8, ​​​​'大刚'​​​​, 3); ​



​INSERT​​​​INTO​​​​TB_STUDENT (ID, ​​​​NAME​​​​, CLASS_ID) ​​​​VALUES​​​​(9, ​​​​'大王'​​​​, 3); ​





初始班级数据

初始学生数据

NO ACTION:

NO ACTION指当删除主表中被引用列的数据时,如果子表的引用列中包含该值,则禁止该操作执行。

现在学生外键级联删除是NO ACTION,执行删除班级操作。

--删除三班 


1




​DELETE​​​​FROM​​​​TB_CLASS ​​​​WHERE​​​​ID=3; ​





Oracle会提示违反完整性约束,如图所示。

如果想要删除三班,必须先删除三班的学生。

--删除三班学生 


1




​DELETE​​​​FROM​​​​TB_STUDENT ​​​​WHERE​​​​CLASS_ID=3; ​





--删除三班 



1




​DELETE​​​​FROM​​​​TB_CLASS ​​​​WHERE​​​​ID=3; ​





SET NULL:

SET NULL指当删除主表中被引用列的数据时,将子表中相应引用列的值设置为NULL值。SET NULL有个前提就是外键引用列必须可以设置为NULL。

把学生表(TB_STUDENT)的外键删除行为改为SET NULL。ORACLE似乎没有MODIFY CONSTRAINT操作,只能先删除外键,然后创建新的。

--删除学生表(TB_STUDENT)表的外键 



1




​ALTER​​​​TABLE​​​​TB_STUDENT ​​​​DROP​​​​CONSTRAINT​​​​FK_TB_STUDENT_CLASS_ID; ​





--删除添加ON DELETE SET NULL外键  


复制代码 代码如下:



ALTER TABLE TB_STUDENT ADD CONSTRAINT FK_TB_STUDENT_CLASS_ID FOREIGN KEY (CLASS_ID) REFERENCES TB_CLASS (ID) ON DELETE SET NULL; 



--删除一班 



1




​DELETE​​​​FROM​​​​TB_CLASS ​​​​WHERE​​​​ID=1; ​





由于外键的ON DELETE是SET NULL,所以当删除一班时,一班学生的CLASS_ID被设置为NULL,如图所示。

CASCADE

CASCADE指当删除主表中被引用列的数据时,级联删除子表中相应的数据行。

把学生表(TB_STUDENT)的外键删除行为改为CASCADE。

--删除TB_STUDENT表上的NO ACTION外键 


1




​ALTER​​​​TABLE​​​​TB_STUDENT ​​​​DROP​​​​CONSTRAINT​​​​FK_TB_STUDENT_CLASS_ID; ​





--删除添加ON DELETE CASCADE外键  


1




​ALTER​​​​TABLE​​​​TB_STUDENT ​​​​ADD​​​​CONSTRAINT​​​​FK_TB_STUDENT_CLASS_ID ​​​​FOREIGN​​​​KEY​​​​(CLASS_ID) ​​​​REFERENCES​​​​TB_CLASS (ID) ​​​​ON​​​​DELETE​​​​CASCADE​​​​; ​






--删除二班 



1




​DELETE​​​​FROM​​​​TB_CLASS ​​​​WHERE​​​​ID=2; ​





由于外键的ON DELETE是CASCADE,所以当删除二班时,二班下的学生也会被删除。

级联更新

Oracle本身并不支持外键的级联更新,不过可以按照如下方法达到级联更新的效果。

首先要先了解Oracle延迟约束和非延迟约束。非延迟约束就是在修改记录的时候会立刻进行约束条件的查看,是否因为违反了某些约束条件而不能执行修改。延迟约束不会在刚进行修改的时候进行约束查看,只有提交的时候才会检查。Oracle的级联更新就是使用这个特性来实现的。

Oracle的外键默认是非延迟约束,修改学生的外键为延迟约束。

--删除学生表(TB_STUDENT)上的已有外键 



1




​ALTER​​​​TABLE​​​​TB_STUDENT ​​​​DROP​​​​CONSTRAINT​​​​FK_TB_STUDENT_CLASS_ID; ​





--添加延迟约束外键 



1




​ALTER​​​​TABLE​​​​TB_STUDENT ​​​​ADD​​​​CONSTRAINT​​​​FK_TB_STUDENT_CLASS_ID ​​​​FOREIGN​​​​KEY​​​​(CLASS_ID) ​​​​REFERENCES​​​​TB_CLASS (ID) ​​​​ON​​​​DELETE​​​​CASCADE​​​​DEFERRABLE; ​





设置触发器,当班级表(TB_CLASS)的主键改变了,就更新学生表(TB_STUDENT)的外键(CLASS_ID)。



1


2


3


4


5


6


7


8




​CREATE​​​​OR​​​​REPLACE​​​​TRIGGER​​​​TGR_TB_CLASS_UPDATE ​



​AFTER​​​​UPDATE​​​​OF​​​​ID ​​​​ON​​​​TB_CLASS ​



​FOR​​​​EACH ROW ​



​BEGIN​



​ ​​​​IF :<>:NEW.ID ​​​​THEN​



​ ​​​​UPDATE​​​​TB_STUDENT ​​​​SET​​​​CLASS_ID=:NEW.ID ​​​​WHERE​​​​CLASS_ID=:; ​



​ ​​​​END​​​​IF; ​



​END​​​​; ​





注意:

Oracle外键级联更新方法可以用于外键和外键引用的主键在不同表上。不过会经常遇到以下情况,就是在数据库中保存具有层级关系的数据时,表的外键引用同一个表的主键。这时候无法用触发器实现级联更新。