MYSQL--- 表的设计

(一).表的设计

在设计表之前,我们需要从需求中获得实体,实体就是在数据库中的一张张的表,实体的属性就是表中的字段(列),然后确定实体与实体之间的关系,然后使用SQL去创建具体的表。

(二).三大范式

在设计表的时候会尊少一些规则,这些规则被称为三大范式

范式描述的就是数据关系的模型 ,分别为 "一对一关系","一对多关系","多对多关系"

范式的分类第一范式,第二范式,第三范式,BC范式,这里重点讲解第一范式,第二范式,第三范式

1.第一范式

表中的字段不可再进行拆分

第一范式是关系型数据库的一个最基本的要求,如果不满足第一范式就不能被称为关系型数据库。

示例:

描述一个学生的信息

反例
sql 复制代码
create table if not exists student2(
	id bigint primary key auto_increment,
	name varchar(20) not null,
	age int,
	shcool varchar(50)
);

上面SQL代码是我创建的一个 "学生"表的代码,包含了编号、名字、年龄和学校

此时这个 "学生"表就不满足第一范式,因为,没有一个数据类型用来表示学校,学校还可以分为 "学校名称","学校地址","学校电话"

正例
sql 复制代码
create table if not exists student1(
	id bigint primary key auto_increment,
	name varchar(20) not null,
	age int,
	school_name varchar(20),
	school_address varchar(50),
	school_tele varchar(20)
);

这个 "学生"表就满足第一范式了,因为我们将 "学校"拆分开了

虽然这样设计表不符合数据库设计的规范,但是每一列都是不可再分的,最起码可以表明一个学生和班级以及学校之间的关系。

注意:在定义表的时候,如果每个字段都可以用一个数据类型表示,那么当前这个表就天然满足第一范式

2.第二范式

在满足第一范式和存在复合主键的基础上,不存在非关键字段对任意候选键的部分函数依赖

非关键字段:非主键字段(下面例子中的 "age" "name")

候选键:主键,外键,没有主键时的唯一键(下面例子中的id)

复合主键:一个表中不能存在两个主键,但是一个主键可以包含多个列

示例:

学生选公开课,公开课都有相应的学分,学生考试之后会生成相应的考试成绩

反例:
sql 复制代码
create table student3(
	id bigint primary key auto_increment,
	name varchar(20) not null,
	age int,
	class varchar(30),
	credit int,
	score decimal(5,2)
);

其实,我们可以发现,"name"字段和 "age"字段可以通过 "id" 字段来确定,"credit"字段可以通过"class"字段来确定,"score"字段是通过"id"字段和"class"字段共同来确认。

也就是说,这个"成绩表"可以通过 "学生id" 和 "class"为复合主键来确定。

学生的"name"字段和"age"字段与 "class"字段并没有关系,它俩只依赖于学号,不依赖于课程。同时,"credit"字段和学生没关系,他只依赖于 "class"字段,不依赖于学生。

对于由两个或者多个关键字段决定一条记录的情况,如果一行数据中有些字段只与关键字段中的一个有关系,例如:"age"字段和"name"字段只与学生的id有关系,那么就说这个表存在函数依赖,那么就不满足第二范式。

正例:

可以设计三个表:学生表,课程表,成绩表

sql 复制代码
-- 学生表
create table student4(
	id bigint primary key auto_increment,
	name varchar(50) not null,
	age int
);

-- 课程表
create table class(
	id bigint primary key auto_increment,
	name varchar(50),
	credit int
);

-- 成绩表
create table score(
	id bigint primary key auto_increment,
	student_id bigint,
	class_id bigint,
	score decimal(5,2),
	-- 通过外键建立关系
	foreign key (student_id) references student4(id), 
	foreign key (class_id) references class(id)
);

这样设计表,每张表都有非主键的字段,都依赖于主键,满足第二范式

如果一张表中没有复合主键,只有主键一列,那么这个表就天然满足第二范式

不满足第二范式会出现的问题

就拿这张表说吧

(1).数据冗余

"name"字段,"age"字段 和 "credit"字段,都重复出现,造成了大量数据的冗余

(2).更新异常

当我要修改MYSQL的学分,就需要更新所有记录中关于MYSQL的记录,如果某些更新成功,某些更新失败,就会造成数据表中的同一门课的不同学分的情况,从而造成数据不一致

(3).插入异常

每一门课都与学生的考试成绩是对应关系,只有同学考试之后才会生成关于这门课的成绩记录,也就是说,在学生未考试之前是没有相应的记录的,因为学生成绩为空是没有意义的

(4).删除异常

当删除记录的时候,课程的学分也会随之删除,这样会导致数据库中没有课程和学分的相应信息

3.第三范式

在第二范式的基础上,不存在非关键字段,对任意候选键的传递依赖

示例:

描述学生就读的学院

反例
sql 复制代码
create table student5(
	id bigint primary key auto_increment,
	name varchar(20),
	age int,
	college varchar(20),
	college_address varchar(20),
	college_tele varchar(20)
);

这个表本质上就记录了学生和学院这两个实体

由于描述的是学生,所以id作为主键

在这个表中,"id"字段和 "name"字段与 "age"字段是强相关的;"college"字段和"college_address"与 "college_tele"字段是强相关的

所以,在这个表中,出现两种强相关关系,同时这两种强相关关系存在传递现象

通过学号可以找到就读的学院,通过就读的学院就可以找到学院的地址和学院的电话

这种传递关系被称为传递依赖

因此这种设计不满足第三范式,原因是存在传递依赖

其实,想要描述清除学生所在的学院,只需要把学生和学院建立一个关联关系即可

正例:

创建两个表,一个学院表,一个学生表

sql 复制代码
-- 创建学院表
create table college(
	id bigint primary key auto_increment,
	name varchar(20),
	address varchar(20),
	tele varchar(20)
);

-- 创建学生表
create table student6(
	id bigint primary key auto_increment,
	name varchar(20),
	age int,
	college_id bigint,
	foreign key (college_id) references college(id) --通过外键连接
);

这样的设计,两张表都依赖于自己表中的主键,学生表都可以通过外键与学院表建立关联关系

(三).实体之间的关系

1.一对一

一对一关系,一般都会存在两个实体

针对一对一的关系,有两种方式来设计表

方式1:将两个实体所有的信息都集中到一张表中

方式2:创建两张表,分别记录两个实体的信息,并把这两张表做关联

示例:

一个人只有一个身份证号

方式一:将人的信息和身份证上的信息集中到一张表中
sql 复制代码
create table people1(
	id bigint primary key auto_increment,
	name varchar(20),
	age int,
	idNumber bigint comment '身份证号',
	date_of_Birth timestamp comment '出生日期' 
);
方式二:创建两张表,分别记录两个实体的信息,并把这两张表做关联
sql 复制代码
-- 创建身份证表
create table ID_card(
	idNumber bigint primary key comment '身份证号',
	name varchar(20) comment '姓名',
	date_of_Birth timestamp comment '出生日期' 
);

-- 创建人表
create table people(
	id bigint primary key auto_increment,
	name varchar(20),
	age int,
	id_card_number bigint,
	-- 关联方法1:在people中使用外键关联ID_card中的idNumber
	foreign key (id_card_number) references ID_card(idNumber)
);
sql 复制代码
-- 创建身份证表
create table ID_card(
	idNumber bigint primary key comment '身份证号',
	name varchar(20) comment '姓名',
	date_of_Birth timestamp comment '出生日期' 
	-- 关联方法2:在ID_card中使用外键关联people中的id
	foreign key (idNumber) references people(id);
);

-- 创建人表
create table people(
	id bigint primary key auto_increment,
	name varchar(20),
	age int,
	id_card_number bigint,
);

两种关联方法选一个即可

2.一对多

示例:

学生和班级之间关系,一个学生只能存在于一个班级,而一个班级可以有很多学生

在学生的角度是多对一的关系,在班级的角度是一对多的关系

我们可以创建两个表,一个是学生表,一个是班级表,然后在学生表中使用外键和班级表创建关联关系,即通过学生表中的class_id就可以表示学生在哪个班级

sql 复制代码
-- 创建班级表
create table class(
	id bigint primary key auto_increment,
	name varchar(20)
);

-- 创建学生表
create table student7(
	id bigint primary key auto_increment,
	name varchar(20),
	class_id bigint,
	foreign key (class_id) references class(id) -- 通过外键建立联系
);

3.多对多

示例:

学生选课程

一个学生可以选择多门课程

同样,一门课程也可以被多名学生选择

我们需要创建三个表,分别是 "学生表","课程表","关系表","学生和课程之间的关系"表

sql 复制代码
-- 创建学生表
create table student8(
	id bigint primary key auto_increment,
	name varchar(20)
);

-- 创建课程表
create table course(
	id bigint primary key auto_increment,
	name varchar(20),
	credit int
);

-- 创建关系表
create table student_course(
	id bigint primary key auto_increment,
	student_id bigint,
	course_id bigint,
	foreign key (student_id) references student8(id),
	foreign key (course_id) references course(id)
);

4.没有关系

没有关系的表,我们直接创建即可,不需要考虑其他的关系

相关推荐
数据知道2 小时前
PostgreSQL的连接方式有哪些?有哪些连接工具?
数据库·postgresql
WJX_KOI2 小时前
保姆级教程:Apache Seatunnel CDC(standalone 模式)部署 MySQL CDC、PostgreSQL CDC 及使用方法
java·大数据·mysql·postgresql·big data·etl
柚子科技2 小时前
毕业设计不用愁:一个免费的 SQL 转 ER 图在线工具,真香!
数据库·sql·毕业设计·课程设计·毕设
xuefuhe2 小时前
postgresql获取真正的execution plan
数据库·postgresql
xcLeigh2 小时前
KingbaseES数据库:ksql 命令行从建表到删表实战(含避坑指南)
数据库·增删改查·国产数据库·金仓数据库
我是黄骨鱼2 小时前
【零基础学数据库|第五篇】DDL语句的使用
数据库
鸽芷咕2 小时前
从 Query Mapping 到函数缓存,KingbaseES 高级 SQL 调优手段全揭秘
数据库·sql·缓存·金仓数据库
Dxy12393102162 小时前
MySQL的DATETIME字段如何避免隐式转换:索引优化与范围查询实践
数据库·mysql
大鹏说大话2 小时前
SQL Server 触发器实战全解:用对是利器,用错是灾难
数据库·sql·mysql