古人已用三冬足,年少今开万卷余。这篇文章主要讲述MySQL数据库(25):外键 foreing key相关的知识,希望能为你提供帮助。
外键 foreing key外键表示了两个实体之间的联系
外键 foreing key: A表中的一个字段的值指向另B表的主键
- B: 主表
- A: 从表
主表:主键(主关键字) = 从表:外键(外关键字)
1、外键操作 1.1、增加外键
基本语法
方式一:创建表的时候增加外键
[constraint `外键名`] foreign key (外键字段) references 主表(主键);
方式二:创建表后增加外键
alter table 从表 add [constraint `外关键字`] foreign key (外键字段) references 主表(主键);
示例1: 创建表的时候增加外键
-- 创建外键
create table my_foreign(
id int primary key auto_increment,
name varchar(10) not null,
class_id int,
-- 创建时,会自动增加普通索引
foreign key (class_id) references my_class(id)
);
mysql>
show create table my_foreign;
CREATE TABLE `my_foreign` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_general_ci NOT NULL,
`class_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `class_id` (`class_id`),
CONSTRAINT `my_foreign_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_cimysql>
desc my_foreign;
+----------+-------------+------+-----+---------+----------------+
| Field| Type| Null | Key | Default | Extra|
+----------+-------------+------+-----+---------+----------------+
| id| int(11)| NO| PRI | NULL| auto_increment |
| name| varchar(10) | NO|| NULL||
| class_id | int(11)| YES| MUL | NULL||
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
MUL多索引 外键本身也是索引
示例2: 创建表后增加外键
-- 查看原来的表
mysql>
desc my_class;
+-------+-------------+------+-----+---------+----------------+
| Field | Type| Null | Key | Default | Extra|
+-------+-------------+------+-----+---------+----------------+
| id| int(11)| NO| PRI | NULL| auto_increment |
| name| varchar(10) | NO| UNI | NULL||
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)mysql>
show create table my_class;
CREATE TABLE `my_class` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_cimysql>
desc my_student;
+----------+-------------+------+-----+---------+----------------+
| Field| Type| Null | Key | Default | Extra|
+----------+-------------+------+-----+---------+----------------+
| id| int(11)| NO| PRI | NULL| auto_increment |
| name| varchar(10) | YES|| NULL||
| class_id | int(11)| YES|| NULL||
| age| int(11)| YES|| NULL||
| gender| int(11)| YES|| NULL||
+----------+-------------+------+-----+---------+----------------+mysql>
show create table my_student\\G
*************************** 1. row ***************************
Table: my_student
Create Table: CREATE TABLE `my_student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL,
`class_id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`gender` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci-- 增加外键
alter table my_student add constraint fk_class_id foreign key (class_id) references my_class(id);
mysql>
show create table my_student\\G
*************************** 1. row ***************************
Table: my_student
Create Table: CREATE TABLE `my_student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL,
`class_id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`gender` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_class_id` (`class_id`),
CONSTRAINT `fk_class_id` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
1.2、删除外键
外键不允许修改,只能先删除再添加
alter table 从表 drop foreign key 外键名字;
示例
alter table my_student drop foreign key `fk_class_id`;
mysql>
show create table my_student\\G
*************************** 1. row ***************************
Table: my_student
Create Table: CREATE TABLE `my_student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL,
`class_id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`gender` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_class_id` (`class_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
外键不会删除普通索引,只会删除外键
删除普通索引
alter table 表名 drop index 索引名字;
1.3、外键的基本要求
- 外键字段需要与关联的主表的主关键字段类型完全一致
- 基本属性也要相同
- 如果是表后增加外键,对数据还有一定的要求(从表数据与主表的关联关系)
- 外键只能使用innodb存储引擎,myisam不支持
2.1、约束的基本概念
当外键产生时,外键所在的表(从表)会受制于主表数据的存在,从而导致数据不能进行某些不符合规范的操作
不能插入主表不存在的数据
如果一张表被其他表外键引入,那么该表的数据操作不能随意,必须保证从表数据的有效性,不能随意删除一个被从表引入的记录
mysql>
select * from my_class;
+----+--------+
| id | name|
+----+--------+
|1 | 一班|
|3 | 三班|
|2 | 二班|
+----+--------+insert into my_foreign (name, class_id) values (张飞, 1);
Query OK, 1 row affected (0.01 sec)-- 主表没有id=4的记录,从表不能插入该数据
insert into my_foreign (name, class_id) values (张飞, 4);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`mydatabase`.`my_foreign`, CONSTRAINT `my_foreign_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`))mysql>
select * from my_foreign;
+----+--------+----------+
| id | name| class_id |
+----+--------+----------+
|1 | 张飞|1 |
+----+--------+----------+
1 row in set (0.00 sec)-- 从表中引用了id=1的记录,该数据不能被删除
delete from my_class where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`mydatabase`.`my_foreign`, CONSTRAINT `my_foreign_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`))
2.2、外键约束的概念
基本语法
add foreign key (外键字段) references 主表(主键) on 约束模式;
约束模式有三种
- district严格模式 默认,不允许操作
- cascade级联模式,一起操作,主表变化,从表的数据也跟着变化
- set null 置空模式 主表变化(删除),从表对应记录设置,前提是从表中对应的外键字段允许为空
通常在进行约束的时候,需要制定操作,update 和 delete
常用的模式
-- 更新级联, 删除置空, 空格隔开
on update cascade on delete set null;
-- 增加约束模式
alter table my_student
add foreign key (class_id) references my_class(id)
on update cascade on delete set null;
mysql>
show create table my_student\\G
*************************** 1. row ***************************
Table: my_student
Create Table: CREATE TABLE `my_student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL,
`class_id` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`gender` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `class_id` (`class_id`),
CONSTRAINT `my_student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_cimysql>
select * from my_class;
+----+--------+
| id | name|
+----+--------+
|1 | 一班|
|3 | 三班|
|2 | 二班|
+----+--------+
3 rows in set (0.00 sec)mysql>
select * from my_student;
+----+--------+----------+------+--------+
| id | name| class_id | age| gender |
+----+--------+----------+------+--------+
|1 | 刘备|1 |18 |2 |
|2 | 李四|1 |19 |1 |
|3 | 王五|2 |20 |2 |
|4 | 张飞|2 |21 |1 |
|5 | 关羽|NULL |22 |2 |
|6 | 曹操|1 |20 |NULL |
+----+--------+----------+------+--------+
6 rows in set (0.00 sec)-- 更新主表
update my_class set id = 4 where id = 2;
-- 从表中所有class_id=2 的记录被修改为了 class_id=4
mysql>
select * from my_student;
+----+--------+----------+------+--------+
| id | name| class_id | age| gender |
+----+--------+----------+------+--------+
|1 | 刘备|1 |18 |2 |
|2 | 李四|1 |19 |1 |
|3 | 王五|4 |20 |2 |
|4 | 张飞|4 |21 |1 |
|5 | 关羽|NULL |22 |2 |
|6 | 曹操|1 |20 |NULL |
+----+--------+----------+------+--------+-- 删除主表数据
delete frommy_class where id = 4;
-- 从表中记录class_id=4被修改为class_id=null;
mysql>
select * from my_student;
+----+--------+----------+------+--------+
| id | name| class_id | age| gender |
+----+--------+----------+------+--------+
|1 | 刘备|1 |18 |2 |
|2 | 李四|1 |19 |1 |
|3 | 王五|NULL |20 |2 |
|4 | 张飞|NULL |21 |1 |
|5 | 关羽|NULL |22 |2 |
|6 | 曹操|1 |20 |NULL |
+----+--------+----------+------+--------+
6 rows in set (0.00 sec)
2.3、约束的作用
保证数据的完整性,主表与从表的数据要一致
【MySQL数据库(25)(外键 foreing key)】正是因为外键有非常强大的数据约束作用,而且可能导致数据再后台变化的不可控性,导致程序在设计开发逻辑的时候,没有办法很好的把握数据,所以外键很少使用
推荐阅读
- MYSQL group by 怎么能快一点,之别一根筋
- MYSQL 8 统计信息持久化 与 null
- PostgreSQL Template
- MYSQL 5.7 VS 8 用函数你三思,三思
- 如何设计出一个比较合理的数据归档系统
- PostgreSQL 如何“霸占”系统OS cache 提升查询性能
- 看电影也可以学点什么
- gitlab安装与使用
- MYSQL怎么发现处理没有commit 留下的“大”麻烦()