目录
外键约束
对数据表进行初期设计,暂时不使用外键
验证限制三
验证级联删除
设置级联更新
Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645
外键约束
外键约束主要是在父子表关系中体现的一种约束操作。
下面通过一个具体的操作来观察一下为什么会有外键约束的存在。
例如,现在希望描述一种概念,两个人有多本书,如果要设计表就需要设计两张数据表
对数据表进行初期设计,暂时不使用外键
-- 删除数据表
DROP TABLE member PURGE ;
DROP TABLE book PURGE ;
-- 创建数据表
CREATE TABLE member(
mid NUMBER ,
name VARCHAR2(20) ,
CONSTRAINT pk_mid PRIMARY KEY(mid)
) ;
CREATE TABLE book(
bid NUMBER ,
title VARCHAR2(20) ,
mid NUMBER
) ;
上面这段代码创建两个数据表,member 和 book 数据表,下面分别向这两张表增加一些数
INSERT INTO member(mid,name) VALUES (1,'张三') ;
INSERT INTO member(mid,name) VALUES (2,'李四') ;
INSERT INTO book(bid,title,mid) VALUES (10,'Java开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (11,'Oracle开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (12,'Android开发',2) ;
INSERT INTO book(bid,title,mid) VALUES (13,'Object-C开发',2) ;
但是此时,也有可能会增加如下信息
INSERT INTO book(bid,title,mid) VALUES (20,'精神病防治',9) ;
此时 member 表中并没有编号为 9 的成员信息
但是由于此时没有设置所谓的约束,所以即使现在父表(member)中不存在对应的编号,那么子表也可以使用,这就是一个错误
实际上也就发现了,book 表中的 mid 列的内容的取值应该由 member 表中的 mid 列所决定,所以现在就可以利用外键约束来解决此类问题
在设置外键约束的时候必须要设置指定的外键列(book.mid列)需要与哪张表的哪个列有关联
-- 删除数据表
DROP TABLE member PURGE ;
DROP TABLE book PURGE ;
-- 创建数据表
CREATE TABLE member(
mid NUMBER ,
name VARCHAR2(20) ,
CONSTRAINT pk_mid PRIMARY KEY(mid)
) ;
CREATE TABLE book(
bid NUMBER ,
title VARCHAR2(20) ,
mid NUMBER ,
CONSTRAINT fk_mid FOREIGN KEY(mid) REFERENCES member(mid)
) ;
上面的代码中,在 member 表中创建了一个主键字段 mid,在 book 表中 mid 字段创建了外键
这个外键和 member 数据表中字段 mid 建立关联,此时 book.mid 列的内容取值范围由 member.mid 列所决定。如果内容正确,则可以保存。
此时可以和前面所述一样,分别向两个表中插入数据
INSERT INTO member(mid,name) VALUES (1,'张三') ;
INSERT INTO member(mid,name) VALUES (2,'李四') ;
INSERT INTO book(bid,title,mid) VALUES (10,'Java开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (11,'Oracle开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (12,'Android开发',2) ;
INSERT INTO book(bid,title,mid) VALUES (13,'Object-C开发',2) ;
如果此时增加错误的数据,来看一下会出现什么情况。向数据表 book 中增加错误的数据,member.mid 没有为 9 的数据
INSERT INTO book(bid,title,mid) VALUES (20,'精神病防治',9) ;
那么此时会出现如下错误信息
ORA-02291: 违反完整约束条件 (SCOTT.FK_MID) - 未找到父项关键字
所谓的外键,就相当于子表中的某一个字段的内容由父表来决定其具体的数据范围。
对外键而言,比较麻烦的是它存在有许多限制。限制一:在删除父表时,需要先删除掉它所对应的全部子表。
member 是父表,book 是子表,如果说现在 book 表没有删除,那么 member 表就无法删除
drop table member;
使用上面代码会出现如下错误信息
ORA-02449: 表中的唯一 / 主键被外键引用
所以需要改变删除顺序
drop table member;
drop table member;
但是有些时候,一些数据库设计者,将 A 表作为 B 表的父表,B 表也同时设置为 A 表的父表,于是就都删不掉了。
为此,在 Oracle 里面专门提供了一个强制删除父表的操作,删除之后不关心子表
drop table member cascade constraint;
此时将强制删除 member 表,但子表不会被删除。但是从实际开发来说,尽量还是按照先后顺序删除。
限制二:如果要作为子表外键的父表列,那么这个列必须设置唯一约束或主键约束。
例如,上面的范例中 member 表中 mid 列被设置成主键约束。
限制三:如果现在主表中某一行数据有对应的子表数据,那么必须先删除子表中的全部数据之后才可以删除父表中的数据。
下面通过一个范例,来理解这个限制的真实意义
验证限制三
首先运行下面代码,建立数据表,并向数据表中插入数据
-- 删除数据表
DROP TABLE book PURGE ;
DROP TABLE member PURGE ;
-- 创建数据表
CREATE TABLE member(
mid NUMBER ,
name VARCHAR2(20) ,
CONSTRAINT pk_mid PRIMARY KEY(mid)
) ;
CREATE TABLE book(
bid NUMBER ,
title VARCHAR2(20) ,
mid NUMBER ,
CONSTRAINT fk_mid FOREIGN KEY(mid) REFERENCES member(mid)
) ;
INSERT INTO member(mid,name) VALUES (1,'张三') ;
INSERT INTO member(mid,name) VALUES (2,'李四') ;
INSERT INTO book(bid,title,mid) VALUES (10,'Java开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (11,'Oracle开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (12,'Android开发',2) ;
INSERT INTO book(bid,title,mid) VALUES (13,'Object-C开发',2) ;
运行上面的代码后,可以观察到,member 和 book 数据表中都有 mid 为 1 的数据,即 member 和book 表中有对应的关联
运行下面的删除语句
DELETE FROM member WHERE mid=1 ;
这时会出现如下错误信息
ORA-02292: 违反完整约束条件 (SCOTT.FK_MID) - 已找到子记录
发生这种错误是由于 book 表中有子记录,所以父表的记录就无法删除了。
如果说现在不想受到子记录的困扰,那么就可以使用级联操作。
级联的关系有两种:级联删除、级联更新。级联删除:在父表数据已经被删除的情况下,自动删除其对应子表的数据。
在定义外键的时候使用 ON DELETE CASCADE 即可
验证级联删除
-- 删除数据表
DROP TABLE book PURGE ;
DROP TABLE member PURGE ;
-- 创建数据表
CREATE TABLE member(
mid NUMBER ,
name VARCHAR2(20) ,
CONSTRAINT pk_mid PRIMARY KEY(mid)
) ;
CREATE TABLE book(
bid NUMBER ,
title VARCHAR2(20) ,
mid NUMBER ,
CONSTRAINT fk_mid FOREIGN KEY(mid) REFERENCES member(mid) ON DELETE CASCADE
) ;
INSERT INTO member(mid,name) VALUES (1,'张三') ;
INSERT INTO member(mid,name) VALUES (2,'李四') ;
INSERT INTO book(bid,title,mid) VALUES (10,'Java开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (11,'Oracle开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (12,'Android开发',2) ;
INSERT INTO book(bid,title,mid) VALUES (13,'Object-C开发',2) ;
在上面代码中,在 book 数据表中定义外键的时候,使用了“ON DELETE CASCADE”。运行下面的删除语句
DELETE FROM member WHERE mid=1 ;
我们可以看到,此时当删除了父表数据之后,子表数据会同时删除掉。
级联更新:如果删除父表数据的时候,不想子表含有关联数据的记录也同时被删除掉,但是这时外键字段的值没有对应的关联数据了,那么对应的子表数据的外键字段就可以设置为 null。这种结果可以使用 ON DELETE SET NULL 设置
设置级联更新
-- 删除数据表
DROP TABLE book PURGE ;
DROP TABLE member PURGE ;
-- 创建数据表
CREATE TABLE member(
mid NUMBER ,
name VARCHAR2(20) ,
CONSTRAINT pk_mid PRIMARY KEY(mid)
) ;
CREATE TABLE book(
bid NUMBER ,
title VARCHAR2(20) ,
mid NUMBER ,
CONSTRAINT fk_mid FOREIGN KEY(mid) REFERENCES member(mid) ON DELETE SET NULL
) ;
INSERT INTO member(mid,name) VALUES (1,'张三') ;
INSERT INTO member(mid,name) VALUES (2,'李四') ;
INSERT INTO book(bid,title,mid) VALUES (10,'Java开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (11,'Oracle开发',1) ;
INSERT INTO book(bid,title,mid) VALUES (12,'Android开发',2) ;
INSERT INTO book(bid,title,mid) VALUES (13,'Object-C开发',2) ;
此时如果运行语句“DELETE FROM member WHERE mid=1”,那么 member 中所有符合条件“mid=1”的行都会被删除掉,
但是对应子表 book 中原先对应的 mid=1 都会更新为 null