外键约束(foreign key) [MySQL][数据库]

外键约束(FOREIGN KEY(字段) REFERENCES 主表名(字段))

外键约束的作用:

限定某个字段的引用完整性

  • 我们之前在讲数据完整性的时候就提到过引用完整性
    • 引用完整性(eg: 员工所在的部门,在部门表中一定要能找到这个部门)

主表和从表:

主表也称之为父表,从表也称之为子表

  • 主表(父表) : 被引用的表
  • 从表(子表) : 引用别人的表
  • 我们如何区分从表和主表?
    • 我们只需要记住: 我们在"从表"中指定外键约束,那么我们就可以知道那个表是从表了,知道了哪个表是从表,那么我们也就知道了哪个表是主表了

外键约束的特点:

  1. 从表的外键列,必须引用主表的主键列或者唯一约束的列

    • 因为被参考的值(也就是被引用的值)必须是唯一的
  2. 在创建外键约束的时候,如果不给外键约束命名,默认的外键约束名不是列名,而是自动产生的一个外键名(例如: student_ibfk_1;)当然我们也可以给外键约束命名

  3. 在创建表时就指定外键约束的话,一定要先创建主表再创建从表

    • 因为如果我们是在创建表的时候创建外键约束,这个时候如果我们直接创建从表,那么由于我们还没有创建主表,这个时候我们却要在从表中引用主表,那么当然执行就会出现错误
  4. 删除表时,要先删除从表(子表),再删除主表(父表)

    • 又或者将外键约束先删除掉,约束没有了,那么怎么删都无所谓了
  5. 当主表的记录被从表参照时,主表的记录将不允许被删除,如果我们要删除数据,则要先删除从表中依赖该记录的数据,然后才可以删除主表中的数据

  6. 当"从表"中指定外键约束,并且一个表中可以有多个外键约束

  7. 从表中的外键列与主表被参照的列的列名可以不相同,但是数据类型一定是相同的,逻辑意义一致,如果类型不一样,创建子表时就会出现错误

  8. 当创建外键约束时,系统默认会在所在列上建立对应的普通索引,索引名是外键的约束名

  9. 删除外键约束后,必须手动删除对应的普通索引

那么我们如何添加外键约束?

这里添加外键约束我们还是分为两种方式

方式一: 在CREATE TABLE时添加约束

  • 注意:我们在添加外键约束的时候一般都是将外键约束设置为表级约束,因为以列级约束添加约束的时候不能指定约束名,而我们对于外键约束来讲默认的约束名不是列名,又由于我们删除外键约束的时候要指明外键约束名,因为我们的一个表中可以声明多个外键约束,所以我们就要通过外键约束名来删除外键约束,所以我们最好在创建外键约束的时候最好就指明外键约束名

这里我们通过举例说明如何在CREATE TABLE时添加约束

我们先创建主表:(如下)
CREATE TABLE dept1(
dept_id INT PRIMARY KEY,
dept_name VARCHAR(15)
);
  • 这里我们就是创建了主表(部门表)
然后这里我们创建从表:(如下)
CREATE TABLE emp1(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT,

#表级外键约束
CONSTRAINT fk_emp1_dept_id FOREIGN KEY(department_id) REFERENCES dept1(dept_id)
);
  • 这里我们创建了从表(员工表)
  • 这里使用员工表中的department_id字段和部门表中的dept_id字段建立了外键连接,这个时候部门表就是主表,员工表就是从表
    • 这个时候要注意: 主表中被引用的字段是键列(也就是有唯一性约束或者主键约束)
  • 这里我们添加外键约束的时候通过了表级约束的方式,并使用了constraint关键字对外键约束命名为 fk_emp1_dept_id
  • references关键字的作用就是标示主表中被引用的列

那么有了外键约束之后有什么作用?

这里我们通过举例说明

INSERT INTO emp1
VALUES(1001,'tom',10);
  • 这个时候会添加失败,因为这个时候我们的主表(部门表)中还没有添加部门,那么在从表中添加数据就是添加不进去的 — 因为我们的外键约束的功能就是判断在从表中添加的数据中的外键约束字段的值一定要在主表中被引用的字段的值中找到相同值,否则就判断添加不成功
所以说我们要想在从表(员工表)中添加数据,那么就先要在主表(部门表)中添加数据,先要有部门,那么才能有这个部门的员工
INSERT INTO dept1
VALUES(10,'IT');
  • 这个时候我们就在部门表(主表)中添加了一条记录,也即是添加了10号部门,那么后面我们就可以在员工表中添加数据了,但是注意要添加的员工一定部门id都要为10
这个时候我们再执行一次添加员工的操作
INSERT INTO emp1
VALUES(1001,'tom',10);
然后这个时候我们从表(员工表)中有10号部门的员工了,那么接下来我们就不能删除主表中的id为10的部门了
DELETE FROM dept1
WHERE dept_id = 10;
  • 这个时候就会删除失败,因为我们从表中有10号部门的员工了,这个时候在主表中就不能删除10号部门了,除非先将从表中10号部门的员工删除掉,或者将外键约束删除掉

方式二 : 在ALTER TABLE时添加外键约束

首先我们先创建两个表

  1. 这里我们先创建一个部门表(主表)
CREATE TABLE dept2(
dept_id INT PRIMARY KEY,
dept_name VARCHAR(15)
);
  1. 然后这里我们再创建一个员工表(从表)
CREATE TABLE emp2(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT
);
  • 然后这里我们在ALTER TABLE时添加外键约束
ALTER TABLE emp2
ADD CONSTRAINT fk_emp2_dept_id FOREIGN KEY(department_id) REFERENCES dept2(dept_id);

  • 这里我们就是在员工表中使用员工表中的department_id字段和部门表中的dept_id建立了外键连接(我们的部门表中的dept_id是一个主键列(也就是添加了主键约束)),所以这里外键约束添加也会是成功的

建立了外键约束之后我们可以通过一条指定的SQL语句来查询外键约束是否添加成功

SELECT *
FROM information_schema.`TABLE_CONSTRAINTS`
WHERE table_name = 'emp2';

  • 注意: 这里的 where table_name = ‘emp2’中的’'是一对单引号,表示是字符串,也就是表名,这里时为了判断表名,显然我们就是要对字符串之间进行判断,而不是加着重号和关键字进行区分

我们还要将一件事情: 外键约束等级

  1. Cascade : 在父表上update/delete记录时,同步的update/delete子表中的匹配的记录

  2. Set null : 在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能设置为not null

    • 如果子表外键列设置为not null,那么我们就不能使用Set null的方式,因为这个时候是冲突的,按理我们设置了Set null之后如果我们要修改或者删除主表中的记录的时候就会将从表中的对应的记录的外键列设置为null,但是这个时候我们的从表中的外键列又设置了not null,这样肯定是不行,所以当外键约束等级为Set null时,这个时候就不能将从表中的外键列设置为not null
  3. No action : 如果在子表中有和主表匹配的记录,那么就不允许对主表进行update/delete操作

  4. Restrict : 和No action是一样的

  5. Set default : 这个我们知道就行,不使用

注意: 如果没有指定外键约束等级,就相当于Restrict方式(或者说是No action的方式)
  • Restrict方式和No action方式功能是一样的

这里我们通过一个例子来理解如果给外键约束指定约束等级

eg: 这里我们设置为on update on delete setnull

  1. 我们也还是先创建主表(部门表)
CREATE TABLE dept3(
d_id INT PRIMARY KEY,
d_name VARCHAR(50)
);

  1. 然后紧接着创建从表(员工表)
CREATE TABLE emp3(
e_id INT PRIMARY KEY,
e_name VARCHAR(15),
dept_id INT ,
CONSTRAINT fk_emp3_dept_id FOREIGN KEY(dept_id) REFERENCES dept3(d_id) ON UPDATE CASCADE ON DELETE SET NULL
);

  • 这里我们就是以表级约束的方式为从表中的dept_id字段和主表中的d_id字段建立了外键约束,并且设置了外键约束等级为: on update cascade on delete set null, 也就是对于update操作,我们的外键约束等级是cascade(也就是同步修改),对于delete操作我们的外键约束等级是set null(也就是主表删除之后,从表对应字段设置为null)
  • 这里我们可以发现,我们的外键约束等级是在设置外键约束时给定,通过 : on update 约束等级 on delete 约束等级 的方式
注意:对于外键约束,我们最好采用ON UPDATE CASCADE ON DELETE RESTRIT的方式(也就是修改主表,那么从表跟着修改,但是不允许删除主表中的被外键约束的字段当我们从表中又对应数据时)

那么我们如何删除外键约束?

我们删除外键约束之后要手动的删除外键约束对应的普通索引

我们先删除外键约束

ALTER TABLE emp1
DROP FOREIGN KEY fk_emp1_dept_id;

  • 这里就已经将我们的emp1表中的名为fk_emp_dept_id的外键约束删除了

而在删除了外键约束之后我们要删除这个外键约束对应的普通索引

ALTER TABLE emp1
DROP INDEX fk_emp1_dept_id;

  • 注意: 外键约束对应的普通索引的索引名和外键约束名相同

猜你喜欢

转载自blog.csdn.net/m0_57001006/article/details/123606567