说明:在项目的数据库设计时,表与表之间是有联系的,如学生管理系统中,有部门表,教师表、学生表、课程表等等
一位教师隶属于一个部门,一个部门有多位教师,因此部门表和教师表,是一对多(或者说多对一)的关系;
每位教师/学生的身份证信息都是唯一的,所以教师/学生和身份证信息,是一对一的关系;
每位学生可选多门课,每门课也有多位学生学习,所以学生和课程,是多对多的关系;
综上所述,表与表之间是有联系的,在设计表、操作数据时,不能不考虑到这些情况,不然例如教师隶属某部门(教研部),但部门表中没有此部门(教研部),或者在删除某部门时,没有判断,导致在此之前关联该部门的教师,现在关联了一个不存在的部门。这样,整个表中的数据就乱套了,造成了数据的不完整、不一致。
准备工作:创建部门表、教师表,添加一些数据
# 创建部门表
create table tb_department (
id int auto_increment primary key comment '序列号',
name char(6) not null comment '部门名'
) comment '部门表';
# 创建教师表
create table tb_teacher (
id int auto_increment primary key comment '序列号',
name char(6) not null comment '姓名',
age tinyint not null comment '年龄',
gender char(2) not null comment '性别',
id_care char(18) not null unique comment '身份证号',
d_id int comment '隶属部门'
) comment '教师表';
# 添加部门
insert into tb_department(name) values ('教研部'),('学工部'),('继续教育部');
# 添加教师
insert into tb_teacher
values (null, '张三', 20, '男', '110110190000001010', '1'),
(null, '李四', 30, '女', '110110190000001011', '2'),
(null, '王五', 35, '男', '110110190000001012', '3');
一对多关系,如上面的部门、教师表,是需要保证教师隶属的部门在部门表中是存在记录,有迹可查的。因此,可以在数据库表中多的一方(教师表中),添加字段,来关联一的一方的主键。但仅添加字段,是无法约束数据库的,数据库该删除部门表的记录,还是照删不误。此时,就可以使用到数据库提供的外键约束(Foreign Key)。
(2)添加外键(SQL语句方式)
alter table 表名
add constraint 外键名
foreign key (外键字段) references 外键关联的表(字段);
alter table tb_teacher
add constraint tb_teacher_tb_department_id_fk_2
foreign key (d_id) references tb_department (id);
删除部门,数据库提示错误,不能删除部门表,因为教师表外键关联了部门表。
drop table tb_department;
添加一条教师记录,关联一个不存在部门,同样会报错
insert into tb_teacher values (null, '赵六', 40, '男', '110110190000001013', '4')
至此,一对多关系通过数据库的外键约束,实现了数据的完整性和一致性。
但是这种方式(称为物理外键)不推荐使用,因为这种方式每次删除记录、添加记录时都需要做检查,极大地降低了效率。推荐使用代码建立联系的方式(称为逻辑外键),避免造成数据的不完整、不一致的操作,例如删除记录、添加记录时在业务逻辑层(Service层)做判断。
一对一关系,如教师的身份证信息和教师。如果在教师表中,把每位老师的身份证信息(身份证号、民族、家庭住址、签发机关、身份证有效期)都放在教师表中,教师表中的字段就太多了,影响查询效率。此时,就可以将教师表中的身份证信息,单独成一张表,给这两张表建立一对一联系。可以把外键设置在查询不频繁的表里,减轻另一张表的负担。需要注意,外键需要唯一且不为空。
创建教师身份信息表
create table tb_teacher_card(
id int auto_increment primary key comment '序列号',
card_num char(18) not null unique comment '身份证号',
nation char(10) not null comment '民族',
address char(50) not null comment '家庭住址',
issued char(20) not null comment '签发机关',
lifespan time not null comment '有效期限',
t_id int not null unique comment '隶属哪个老师'
) comment '身份证信息'
多对多关系,如学生和课程表,每个学生可以选多门课程,每门课程可以有多个学生。可以将学生表中的选课字段,课程表中的学生字段,单独创建一张表,称为课程选择表。将学生和课程的多对多关系,转换为学生对课程选择表,课程对课程选择表的一对多关系。
创建学生表、课程表、课程选择表
create table tb_student(
id int auto_increment primary key comment '序列号',
name char(6) not null comment '姓名',
age tinyint comment '年龄',
gender char(2) comment '性别'
) comment '学生表';
create table tb_course(
id int auto_increment primary key comment '序列号',
name char(10) not null comment '课程名'
) comment '课程表';
create table tb_course_student(
id int auto_increment primary key comment '序列号',
c_id int comment '课程',
s_id int comment '学生'
) comment '课程选择表'
在课程选择表(tb_course_student)上建立外键约束,课程、学生字段分别指向课程表(tb_course)、学生表(tb_student)的主键
数据库多表设计的建立原则:
一对多关系:在“多”的一方创建一个字段,这个字段用来关联“一”的一方的主键;(外键,不推荐使用数据库提供的物理外键,建议使用代码约束的逻辑外键)
一对一关系:在任意一方创建外键,外键唯一且不能为空,指向另一方的主键;(建议外键建立在查询不频繁的那张表里面,可以减轻另一张表的负担)
多对多关系:建立一张中间表,中间表至少有2个字段,分别指向各自表的主键;