MySQL —— 表的设计

表的设计

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

在设计表的时候我们会遵守一些规则,这些规则叫做三大范式(范式是描述数据关系的模型),下面我们来了解一下三大范式。

第一范式

第一范式是关系型数据库的一个基本要求,如果不满足第一范式就不是关系型数据库。
第一范式要求表里的字段不能继续拆分

举个例子:

我们定义一个学生表,但是你只是给了一个字段------学生,可是这个学生范围很广泛,有学生的姓名,性别,年龄,班级,学号等等,说明学生这个字段是可以拆分的,所以你最开始定义的表是不符合第一范式的。

如果一张表里的所有的字段都无法拆分那就满足第一方式,还是学生表为例子:现在创建了学号,姓名,性别,年龄这四个字段组成学生表那就符合第一范式,因为每一个字段都是不可分的。

在定义表的时候,对照数据中的数据类型,将每一个字段都可以用一个数据类型表示,那么当前这个表就天然满足第一范式

第二范式

第二范式在满足第一范式的基础上,存在于复合主键的情况下,不存在非关键字段对任意候选键的部分函数依赖
简单来说,对于由两个或者多个关键字段(即复合主键)决定一条记录的情况的时候,如果一行数据中非主键的字段与复合主键的部分字段存在关系,就说明存在部分函数依赖,不满足第二范式

现在举个例子:

假设我有一张学生成绩表,表里有一下这些字段:

这张表设计是存在问题的,首先我们可以假设将学号设置为主键,然后通过学号我们是可以确定这个学生的姓名性别年龄以及班级的,但是再往后看,我们会发现通过课程名称我们应该是可以找到课程的学分,这时候这个课程的成绩到底是由什么决定的,那应该就是学生和课程共同决定的(学生参加这个课程的考试之后就会有成绩),那这时候我们就可以将学号和课程名称定义为复合主键,在这张表中姓名和课程学分就是非关键字段,但是却与候选键发生了函数依赖(也就是存在关系),那么就会违反第二范式。

以上面的学生成绩表为例:

将表进行拆分,学生表(学生学号,姓名,性别,年龄与班级),课程表(课程编号、名称,课程学分),还有一张课程成绩表(学号,课程编号,成绩)。

如果一张表没有复合主键,那么这张表一定满足第二范式。

如果不满足第二范式有什么后果?

  1. 造成数据冗余:就像上面的表,本来我需要查看的是学生考了多少分,但是你还告诉我学生的性别,年龄,班级甚至课程学分我都不想知道,这就是数据冗余,并且很浪费空间,应该让每一张表都有自己特定的数据进行保存,而不是全部塞进去
  2. 更新可能会出现异常:假设你要修改课程对应的学分,那你是不是要把每一个都有这个课程的数据行都要进行修改,不仅费时费力,万一数据库服务器突然坏了一秒钟,你之前更新的数据还不一定会保存下来。
  3. 插入异常,如果你要新增一门新课程,那你怎么往这张表插入数据,设计表的时候有些列不能为空的,那你是不是还要伪造哪些空数据,或者你等到有人考了这门成绩出来以后再加入数据库中(黄瓜菜都凉了)。
  4. 删除异常:假设所有参加 JavaEE 课程的同学都毕业了,但是JavaEE 的新学生还没这么快考试,那你如果删除这些毕业的人的数据的时候,也就连JavaEE 的课程信息也删除了。

如何避免第二范式:

在设计复合主键的时候,一定要考虑清楚其他字段会不会与复合存在部分函数联系。

第三范式

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

以下面的学生表为例:

这张表主键定义为学号,但是我们可以 从学号得知学院名称 再得知学院的地址和电话,由于学院名称是非关键字段,所以存在了传递关系。

那该如何设计这张学生表?

设计成两张表,一个学院表(学院编号,学院名称,学院电话,学院地址)

一张学生表(学号,姓名,学院编号)设计成主外键键关系即可。

表的关系

一对一

举个例子:一个中国公民只有一个身份证

如何设计表:

创建两张表,分别记录中国公民的个人信息(姓名,电话,现居地址),身份证信息(身份证号,姓名,年龄,性别)

然后我们可以再公民表中设计一个外键(身份证号)。

sql 复制代码
create table idcard(
	id bigint primary key comment '身份证号',
	name varchar(20) not null comment '姓名',
	gender varchar(1) not null comment '性别',
	age int not null comment '年龄'
);

create table person(
	id bigint primary key auto_increment comment '编号',
	name varchar(20) not null comment '姓名',
	address varchar(100) comment '现居地址',
	foreign key (id) references idcard(id)
);

一对多(多对一)

举例:一个班级存在很多个学生,这是一对多的关系

同理,很多个学生都在一个班级,这是多对一的关系

如何设计表:

还是一样,先创建不同的实体表,再去建立联系

演示:创建班级表(班级编号,班级人数)

再创建学生表(学生学号,姓名,年龄,所属班级)

最后确定关系,我们可以在学生表添加一个班级外键:

sql 复制代码
create table class(
	id bigint primary key comment '班级编号',
	num int comment '人数'
);

create table student (
	id bigint primary key auto_increment comment '学生学号',
	name varchar(50) not null comment '姓名',
	age int comment '年龄',
	foreign key (id) references class(id)
);

多对多

举个例子:学生与课程的关系,一个学生可以选择很多个课程,一个课程同时也可以包含很多个学生。

如何设计?

首先分别创建好实体表,一张学生表(学生学号,姓名,年龄) 一张课程表(课程编号,课程名称,课程学分)

然后确定关系发现是多对多,那就再创建一张表------关系表(关系表自身的编号,学生学号,课程编号)

sql 复制代码
create table student (
	id bigint primary key auto_increment comment '学生学号',
	name varchar(50) not null comment '姓名',
	age int comment '年龄'
);

create table course(
	id bigint primary key auto_increment comment '课程编号',
	name varchar(20) not null comment '课程名称',
	score decimal(2,1) comment '学分'
);

create table student_course (
	id bigint primary key comment '自身编号',
	student_id bigint not null comment '学生学号',
	course_id bigint not null comment '课程编号',
	foreign key (student_id) references student(id),
	foreign key (course_id) references course(id)
);

我们还可以在这张关系表中添加一个成绩的字段。

没有关系

对于没有关系的表,我们直接设计即可,不需要考虑其与其他的关系(因为本来就没有关系)

相关推荐
Elastic 中国社区官方博客23 分钟前
使用 Elasticsearch 导航检索增强生成图表
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
小金的学习笔记27 分钟前
RedisTemplate和Redisson的使用和区别
数据库·redis·缓存
新知图书42 分钟前
MySQL用户授权、收回权限与查看权限
数据库·mysql·安全
文城5211 小时前
Mysql存储过程(学习自用)
数据库·学习·mysql
沉默的煎蛋1 小时前
MyBatis 注解开发详解
java·数据库·mysql·算法·mybatis
呼啦啦啦啦啦啦啦啦1 小时前
【Redis】事务
数据库·redis·缓存
HaoHao_0101 小时前
AWS Serverless Application Repository
服务器·数据库·云计算·aws·云服务器
C语言扫地僧1 小时前
MySQL 事务及MVCC机制详解
数据库·mysql
小镇cxy1 小时前
MySQL事物,MVCC机制
数据库·mysql
书生-w2 小时前
Redis Windows 解压版安装
数据库·windows·redis