MYSQL-外键约束(图文)

风流意气都作罢 提交于 2020-09-24 07:27:43

简介

外键的使用条件:

  1. 两个表必须是InnoDB表,MyISAM表暂时不支持外键
  2. 外键列必须建立了索引,MySQL 4.1.2以后的版本在建立外键时会自动创建索引
  3. 外键关系的两个表的列必须是数据类型相似,也就是可以相互转换类型的列,比如int和tinyint可以,而int和char则不可以,且被关联字段必须保证唯一

四种外键约束方式

RESTRICT(约束):如果出现在删除时,意思是约束外键主键did记录(主表中的记录)不能直接删除,必须先删除被约束的表(从表)字段中dept_id所有这个外键主键值对应的记录,才能删除外键约束(主表中的记录),测试发现在navicat中不选择默认设置的就是这种

NO ACTION:在MySQL中等同于RESTRICT,原因如下:restrict是在修改或者删除之前去检查从表中是否有对应的数据,如果有,拒绝操作,而no action是来源标准的sql,在有些数据库中,会延迟检查,即在修改或者删除完以后去检查从表中是否有对应的数据,如果有,拒绝操作,但是在MySQL中,外键约束都会立即检查,所以两者等价

CASCADE:删除选择这个时,删除主表中的记录时,主表中的这个主键id关联的从表的这个id值所在的记录也会被删除。建议不选。

SET NULL :删除选择这个时,如果从表(被约束的字段所在的表中)被约束的字段的值设置为可以为空时,那么当删除主表的记录时,主表中被删除的这个记录对应的主键值(约束从表字段的那个值)在从表中对应的字段中出现的那个记录的被约束字段的值就会变为NULL。

最常用的是选择RESTRICT不让删的这个约束、或者选择SET NULL删除后值表为空。

示例

Step 1: 创建两张表:部门表dept 员工表emp,并将emp.dno外键关联到dept.did

CREATE TABLE `dept` (
  `did` int(10) NOT NULL AUTO_INCREMENT,
  `dname` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`did`),
  UNIQUE KEY `dname` (`dname`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `emp` (
  `eid` int(10) NOT NULL AUTO_INCREMENT,
  `ename` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
  `dno` int(10) DEFAULT NULL,
  `sal` double(7,2) DEFAULT NULL,
  PRIMARY KEY (`eid`),
  KEY `fk_dno_did` (`dno`),
  CONSTRAINT `fk_dno_did` FOREIGN KEY (`dno`) REFERENCES `dept` (`did`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

mysql> desc dept;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| did   | int(10)      | NO   | PRI | NULL    | auto_increment |
| dname | varchar(255) | NO   | UNI | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
mysql> desc emp;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| eid   | int(10)     | NO   | PRI | NULL    | auto_increment |
| ename | varchar(30) | YES  |     | NULL    |                |
| dno   | int(10)     | YES  | MUL | NULL    |                |
| sal   | double(7,2) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

Step 2: 初始化表数据

insert into dept values (1,'技术部'),(2,'人事部');
insert into emp values (1,'张三',1,10000),(2,'李四',2,20000);

mysql> select * from dept order by did;
+-----+--------+
| did | dname  |
+-----+--------+
|   1 | 技术部 |
|   2 | 人事部 |
+-----+--------+
mysql> select * from emp order by eid;
+-----+-------+-----+----------+
| eid | ename | dno | sal      |
+-----+-------+-----+----------+
|   1 | 张三  |   1 | 10000.00 |
|   2 | 李四  |   2 | 20000.00 |
+-----+-------+-----+----------+

Step 3:存在关联数据的情况下删除、更新dept数据表,或者插入、更新emp时会报错(四种情况)

delete from dept where did=1;
1451 - Cannot delete or update a parent row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `fk_dno_did` FOREIGN KEY (`dno`) REFERENCES `dept` (`did`))

update dept set did=3 where did=1;
1451 - Cannot delete or update a parent row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `fk_dno_did` FOREIGN KEY (`dno`) REFERENCES `dept` (`did`))

insert into emp values (null,'张三',4,10000);
1452 - Cannot add or update a child row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `fk_dno_did` FOREIGN KEY (`dno`) REFERENCES `dept` (`did`))

update emp set dno=3 where eid=1;
1452 - Cannot add or update a child row: a foreign key constraint fails (`test`.`emp`, CONSTRAINT `fk_dno_did` FOREIGN KEY (`dno`) REFERENCES `dept` (`did`))

扩展:其他约束类型

  1. 主键约束 PRIMARY KEY
  2. 唯一约束 UNIQUE
  3. 非空约束 NOT NULL
  4. 默认值约束 DEFAULT
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!