关联关系介绍
MySQL 是一个关系型数据库, 不仅可以存储数据, 还可以维护数据与数据之间的关系——通过在数据表中添加字段建立外键约束
数据与数据之间的关联关系分为四种:
- 一对一关联
- 一对多关联
- 多对一关联
- 多对多关联
一对一关联
人 —- 身份证 一个人只有一个身份证、一个身份证只对应一个人
学生 —- 学籍 一个学生只有一个学籍、一个学籍也对应唯一的一个学生
用户 —- 用户详情 一个用户只有一个详情、一个详情也只对应一个用户
方案 1: 主键关联 —— 两张数据表中主键相同的数据为相互对应的数据
方案 2: 唯一外键 —— 在任意一张表中添加一个字段添加外键约束与另一张表主键关联, 并且将外键列添加唯一约束
一对多与多对一
班级 —- 学生 (一对多) 一个班级包含多个学生
学生 —- 班级 (多对一) 多个学生可以属于同一个班级
图书 —- 分类 商品 —— 商品类别
方案: 在多的一端添加外键, 与一的一端主键进行关联
多对多关联
学生 —- 课程 一个学生可以选择多门课、一门课程也可以由多个学生选择
会员 —- 社团 一个会员可以参加多个社团、一个社团也可以招纳多个会员
方法: 额外创建一张关系表来维护多对多关联 —— 在关系表中定义两个外键, 分别与两个数据表的主键进行关联
外键约束
外键约束 —— 将一个列添加外键约束与另一张表的主键 (唯一列) 进行关联之后, 这个外键约束的列添加的数据必须要在关联的主键字段中存在
示例: 学生表和班级表
- 先创建班级表
create table classes(class_id int primary key auto_increment,class_name varchar(40) not null unique,class_remark varchar(200));
- 创建学生表 (在学生表中添加外键与班级表的主键进行关联)
# 【⽅式一】在创建表的时候, 定义 cid 字段, 并添加外键约束# 由于 cid 列要与 classes 表的 class_id 进⾏关联, 因此 cid 字段类型和⻓度要与 class_id 一致create table students(stu_num char(8) primary key,stu_name varchar(20) not null,stu_gender char(2) not null,stu_age int not null,cid int,constraint FK_STUDENTS_CLASSES foreign key(cid) references classes(class_id));#【⽅式⼆】先创建表, 再添加外键约束create table students(stu_num char(8) primary key,stu_name varchar(20) not null,stu_gender char(2) not null,stu_age int not null,cid int);# 在创建表之后, 为 cid 添加外键约束alter table studentsadd constraint FK_STUDENTS_CLASSESforeign key (cid) references classes (class_id);# 删除外键约束alter table students drop foreign key FK_STUDENTS_CLASSES;
- 向班级表添加班级信息
insert into classes(class_name, class_remark)values('java2104', '...');insert into classes(class_name, class_remark)values('Java2105', '...');insert into classes(class_name, class_remark)values('Java2106', '...');insert into classes(class_name, class_remark)values('Python2106', '...');select * from classes;+----------+------------+--------------+| class_id | class_name | class_remark |+----------+------------+--------------+| 1 | java2104 | ... || 2 | java2105 | ... || 3 | java2106 | ... || 4 | Python2105 | ... |+----------+------------+--------------+
- 向学生表中添加学生信息
insert into students(stu_num, stu_name, stu_gender, stu_age, cid)values('20210102', '李斯', '⼥', 20, 4);# 添加学生时, 设置给 cid 外键列的值必须在其关联的主表 classes 的 classes_id 列存在insert into students(stu_num, stu_name, stu_gender, stu_age, cid)values('20210103', '王五', '男', 20, 6);
关键约束 - 级联
当学生表中存在学生信息关联班级表的某条记录时,就不能对班级表的这条记录进⾏
修改 ID和删除操作,如下:
select * from classes;+----------+------------+--------------+| class_id | class_name | class_remark |+----------+------------+--------------+| 1 | java2104 | ... || 2 | java2105 | ... || 3 | java2106 | ... || 4 | Python2105 | ... |+----------+------------+--------------+select * from students;+----------+----------+------------+---------+------+| stu_num | stu_name | stu_gender | stu_age | cid |+----------+----------+------------+---------+------+| 20210101 | 张三 | 男 | 20 | 2 || 20210102 | 李斯 | ⼥ | 20 | 4 || 20210103 | 王五 | 男 | 18 | 1 || 20210104 | 赵六 | 女 | 18 | 2 |+----------+----------+------------+---------+------+# 班级表中 class_id = 1 的班级信息被学生表中的记录关联了, 则不能修改 java2104 的 class_id, 并且不能删除update classes set class_id = 5 where class_name = 'java2104';ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`db_test2`.`students`, CONSTRAINT `FK_STUDENTS_CLASS` FOREIGN KEY (`cid`) REFERENCES `classes` (`class_id`))delete from classes where class_id = 1;ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`db_test2`.`students`, CONSTRAINT `FK_STUDENTS_CLASS` FOREIGN KEY (`cid`) REFERENCES `classes` (`class_id`))
如果一定要修改 java2104 的班级 ID, 该如何实现?
- 将引用 java2104 班级 id 的学生记录中的 cid 修改为 NULL
update students set cid = NULL where cid = 1;select * from students;+----------+----------+------------+---------+------+| stu_num | stu_name | stu_gender | stu_age | cid |+----------+----------+------------+---------+------+| 20210101 | 张三 | 男 | 20 | 2 || 20210102 | 李斯 | ⼥ | 20 | 4 || 20210103 | 王五 | 男 | 18 | NULL || 20210104 | 赵六 | 女 | 18 | 2 |+----------+----------+------------+---------+------+
- 再修改班级信息表中 java2104 记录的 class_id
update classes set class_id = 5 where class_name = 'java2104';select * from classes;+----------+------------+--------------+| class_id | class_name | class_remark |+----------+------------+--------------+| 2 | java2105 | ... || 3 | java2106 | ... || 4 | Python2105 | ... || 5 | java2104 | ... |+----------+------------+--------------+
- 将学生表中 cid 设置为 NULL 的记录的 cid 重新修改为 java2104 这个班级的新的 id
update students set cid = 5 where cid IS NULL;select * from students;+----------+----------+------------+---------+------+| stu_num | stu_name | stu_gender | stu_age | cid |+----------+----------+------------+---------+------+| 20210101 | 张三 | 男 | 20 | 2 || 20210102 | 李斯 | ⼥ | 20 | 4 || 20210103 | 王五 | 男 | 18 | 5 || 20210104 | 赵六 | 女 | 18 | 2 |+----------+----------+------------+---------+------+
也可使用
级联操作来实现:
- 在添加外键时, 设置
级联修改和级联删除
# 删除原有的外键alter table students drop foreign key FK_STUDENTS_CLASSES;# 重新添加外键, 并设置级联修改和级联删除alter table students add constraint FK_STUDENTS_CLASSESforeign key(cid) references classes(class_id) ON UPDATE CASCADE ON DELETE CASCADE;
- 测试级联修改
# 修改 java2104 的 class_id, 关联 java2104 这个班级的学⽣记录的 cid 也会同步修改update classes set class_id = 1 where class_name = 'java2104';# 班级信息select * from classes;+----------+------------+--------------+| class_id | class_name | class_remark |+----------+------------+--------------+| 2 | java2105 | ... || 3 | java2106 | ... || 4 | Python2105 | ... || 1 | java2104 | ... |+----------+------------+--------------+# 学生信息select * from students;+----------+----------+------------+---------+------+| stu_num | stu_name | stu_gender | stu_age | cid |+----------+----------+------------+---------+------+| 20210101 | 张三 | 男 | 20 | 2 || 20210102 | 李斯 | ⼥ | 20 | 4 || 20210103 | 王五 | 男 | 18 | 1 || 20210104 | 赵六 | 女 | 18 | 2 |+----------+----------+------------+---------+------+
- 测试级联删除
# 删除 class_id = 1 的班级信息, 学⽣表引⽤此班级信息的记录也会被同步删除delete from classes where class_id=1;# 班级信息select * from classes;+----------+------------+--------------+| class_id | class_name | class_remark |+----------+------------+--------------+| 2 | java2105 | ... || 3 | java2106 | ... || 4 | Python2105 | ... |+----------+------------+--------------+# 学生信息select * from students;+----------+----------+------------+---------+------+| stu_num | stu_name | stu_gender | stu_age | cid |+----------+----------+------------+---------+------+| 20210101 | 张三 | 男 | 20 | 2 || 20210102 | 李斯 | ⼥ | 20 | 4 || 20210104 | 赵六 | 女 | 18 | 2 |+----------+----------+------------+---------+------+
