1、多表关联关系的分类
既然数据库是存储项目中的数据的,项目中的数据主要是类型创建的对象,项目中类型和类型之间是有关系的,数据库中怎么体现出来?
不论是生活中,还是抽象出来的软件中,描述生活中的多个类型之间的关系,总结如下:
- 一对一关系
- 一对多关系、多对一关系
- 多对多关系
2、多表关联关系的实现
可以通过添加外键
来实现。
2.1 一对一
- 主键共享
两张表的主键,建立外键约束。
-- 建立一对一关系:一夫一妻
mysql> create table husband(
-> hid int primary key auto_increment comment '丈夫编号',
-> hname varchar(20) not null comment '丈夫姓名'
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> create table wife(
-> wid int primary key auto_increment comment '妻子编号',
-> wname varchar(20) not null comment '妻子姓名'
-> ,foreign key(wid) references husband(hid)
-> );
Query OK, 0 rows affected (0.02 sec)
-- 测试数据
mysql> insert into husband(hname) values('邓超');
Query OK, 1 row affected (0.01 sec)
mysql> insert into husband(hname) values('张若昀');
Query OK, 1 row affected (0.01 sec)
mysql> insert into wife(wname) values('孙俪');
Query OK, 1 row affected (0.01 sec)
mysql> insert into wife(wname) values('唐艺昕');
Query OK, 1 row affected (0.00 sec)
mysql> insert into wife(wname) values('孙怡');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`power`.`wife`, CONSTRAINT `wife_ibfk_1` FOREIGN KEY (`wid`) REFERENCES `husband` (`hid`))
- 外键唯一
子表添加一个新的字段并给该字段添加唯一约束和外键约束,然后关联父表主键字段。
-- 建立一对一关系:一夫一妻
mysql> create table wife(
-> wid int primary key auto_increment comment '妻子编号',
-> wname varchar(20) not null comment '妻子姓名',
-> w_hid int unique,
-> foreign key (w_hid) references husband(hid));
Query OK, 0 rows affected (0.03 sec)
-- 测试数据:可以不按顺序插入,只要丈夫编号对应即可
mysql> insert into wife(wname,w_hid) values('唐艺昕',2);
Query OK, 1 row affected (0.01 sec)
mysql> insert into wife(wname,w_hid) values('孙俪',1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from wife;
+-----+--------+-------+
| wid | wname | w_hid |
+-----+--------+-------+
| 1 | 唐艺昕 | 2 |
| 2 | 孙俪 | 1 |
+-----+--------+-------+
2 rows in set (0.00 sec)
2.2 一对多
- 外键添加在多的一方,关联一的主键。
-- 建立一对多关系:一个学生有多门课程
mysql> create table stu(
-> id int primary key auto_increment,
-> sname varchar(20) not null);
Query OK, 0 rows affected (0.02 sec)
mysql> create table course(
-> id int primary key auto_increment,
-> cname varchar(50) not null,
-> score int default 0,
-> sid int,
-> foreign key (sid) references stu(id)
-> );
Query OK, 0 rows affected (0.03 sec)
-- 测试数据
mysql> insert into stu (sname) values('zhangsan');
Query OK, 1 row affected (0.01 sec)
mysql> insert into course(cname,score,sid) values('math',98,1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into course(cname,score,sid) values('chinese',99,1);
Query OK, 1 row affected (0.01 sec)
mysql> insert into course(cname,score,sid) values('english',111,1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from course;
+----+---------+-------+------+
| id | cname | score | sid |
+----+---------+-------+------+
| 1 | math | 98 | 1 |
| 2 | chinese | 99 | 1 |
| 3 | english | 111 | 1 |
+----+---------+-------+------+
3 rows in set (0.00 sec)
2.3 多对多
- 外键:两张表的普通字段,直接建立关联关系(不推荐)
- 中间表:创建一个中间表,中间表的两个普通字段分别关联另两张表的主键。
-- 建立多对多关系:一个学生有多个老师,一个老师有多个学生
-- 我这里之前已经创建过学生表
mysql> desc stu;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| sname | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> create table teacher(
-> tid int primary key auto_increment,
-> tname varchar(10));
Query OK, 0 rows affected (0.03 sec)
-- 中间表
mysql> create table stu_tea(
-> id int primary key auto_increment,
-> sid int,
-> tid int,
-> foreign key(sid) references stu(sid),
-> foreign key(tid) references teacher(tid));
Query OK, 0 rows affected (0.02 sec)
总结
- 中小型项目中的数据表,为了避免垃圾数据的出现,强制添加外键约束
项目规模和项目本身对于数据的安全性约束较少,容易产生垃圾数据 - 大型项目并且对数据查询性能较高的数据表,约定的方式关联(不额外添加外键)
项目规模和项目本身对于数据安全性约束较多,不容易产生垃圾数据
不需要额外添加外键提高查询数据时的性能消耗