简介
外键的使用条件:
- 两个表必须是InnoDB表,MyISAM表暂时不支持外键
- 外键列必须建立了索引,MySQL 4.1.2以后的版本在建立外键时会自动创建索引
- 外键关系的两个表的列必须是数据类型相似,也就是可以相互转换类型的列,比如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`))
扩展:其他约束类型
- 主键约束 PRIMARY KEY
- 唯一约束 UNIQUE
- 非空约束 NOT NULL
- 默认值约束 DEFAULT