MySQL初学之旅(4)表的设计


目录

1.前言

2.正文

2.1第一范式

2.2第二范式

2.3第三范式

2.4表的设计方法

3.小结


1.前言

哈喽大家好吖,今天继续给大家分享MySQL的学习------表的设计,这一部分没有太多语法的讲解,有许多设计思路以及规则的讲解与剖析,那么话不多说让我们开始吧。

2.正文

表的设计的核心就是三大范式,在了解核心三大范式之前,让我们先知道范式是什么:

范式(Normal Form)是一套理论规范,用于组织数据库中的数据,旨在减少数据冗余并确保数据的一致性和完整性。范式通过一系列规则指导数据库设计,以避免常见的设计问题(如重复数据、插入异常、更新异常等)。

范式的目标:

  • 减少数据冗余: 避免重复存储相同信息。
  • 消除插入、删除、更新异常: 确保数据的逻辑一致性。
  • 提高数据完整性: 避免由于设计问题导致的错误数据。
  • 便于扩展和维护: 数据库结构清晰,便于修改和扩展。

下文每一条细讲的时候会逐个说明违反哪个原则会出现那种后果

2.1第一范式

先上定义:

  • 原子性: 表中的每一列都只能包含单一值,而不能包含集合、列表或其他复杂结构。
  • 表结构规范化: 每一列的数据类型必须一致。

让我们放到实例中讲解,我们本文均以学生为背景来讲解,假设我们现在要为建一个学生表,那么它包含的信息就应该有:

  • 姓名,id,年龄,学校等信息

当我们在建表的时候就会发现:

sql 复制代码
CREATE table student(
id BIGINT,
name varchar(50),
school 

school这个变量里没有适合它的数据类型,学校可以包括学校的名字,学校的地址,学校的电话等,即学校这个这个字段可以进行拆分,那么这就违反了建表的第一范式。遇到这种情况我们会选择额外建立一张学校表来处理。

还有一种情况不符合,即在创建表时,该字段会被填入俩个及以上数据时,这样也违反了第一范式,一般遇到这种情况,我们可以将一行数据变成俩行,分开存储。

2.2第二范式

定义:

  • 前提条件: 表必须满足第一范式(1NF)。
  • 要求: 所有非主键字段必须完全依赖于主键,不能对主键产生部分依赖。

区分一下什么叫完全依赖,什么叫部分依赖:

  • 部分依赖: 如果一个非主键字段只依赖于主键的一部分,而不是整个主键,就称为部分依赖。
  • 完全依赖: 如果一个非主键字段依赖于主键的全部字段,则称为完全依赖。

看着定义又是完全又是部分,那么到底是什么意思呢,举个例子大家就懂咯:

假设我们现在创建一个有关学生选修课的表:

sql 复制代码
CREATE table student(
id BIGINT,
name varchar(50),
subject VARCHAR(50),--学科
credit BIGINT,--学分
score BIGINT--成绩
);

我们乍看这张表没有问题,包含信息还比较完整,但当我们仔细观察,发现学分这一列只会跟随学科的变化而变化,不会随着学生的变化而变化。那么也就说明当我们在插入足够多的数据的时候,可以想象,有一列完全一样的学科对应着一列完全相同的学分,这样就造成了数据的冗余,这也是违背了第二范式即所有非主键字段必须完全依赖于主键。

所以我们在解决这个问题采用分开建表的方式,分别可以建立三张表:

  • 一个为学生基础信息表。
  • 另一个为课程学分表。
  • 还有一个单独储存成绩的表,因为成绩既和学生有关,又和学科有关,所以放在哪个表中都不合适,所以单独建表。

我们再来专门分析一下如果违反了第二范式会导致什么后果:

  • 数据冗余: 每次记录学生学分名都会重复存储。
  • 更新异常: 修改一个学生的姓名或课程信息时,需要更新多条记录,如果中间更新中断,我们无法确定哪一部分数据已更新,哪一部分数据未更新,会造成数据不一致。
  • 插入异常: 如果课程尚未被选,则无法记录课程信息。既如果新加一个课程,但并没有考试成绩,会导致此时部分空没有意义。
  • 删除异常: 删除某学生的选课记录后,课程信息也会丢失。既某些课程的学分信息被一并删去,且直到下一次再插入数据时均没有该信息,信息会短暂丢失。

以上都是违背了第二范式导致设计不合理的后果,应该严格去遵守这个原则。

2.3第三范式

定义:

  • 前提条件: 表必须满足第二范式(2NF)。
  • 要求: 非主键字段必须直接依赖于主键 ,而不能通过其他非主键字段间接依赖于主键(即,消除传递依赖)。

我们再来明确一下什么是传递依赖:

  • 如果一个非主键字段依赖于另一个非主键字段,而这个非主键字段又依赖于主键,那么就存在传递依赖。

继续举例子详细讲解,假设我们现在这样创建一个表:

学生ID 学生姓名 专业ID 专业名称 专业院长
1 张三 101 计算机 王教授
2 李四 102 数学 李教授

主键:

  • 主键是学生ID

问题:

  • 专业名称专业院长 依赖于专业ID ,而专业ID 又依赖于主键学生ID
  • 这意味着专业名称专业院长 并非直接依赖主键,而是通过专业ID间接依赖于主键,存在传递依赖。

处理方法就是将其拆成俩张表:

学生表:

学生ID 学生姓名 专业ID
1 张三 101
2 李四 102

专业表:

专业ID 专业名称 专业院长
101 计算机 王教授
102 数学 李教授

这样就可以避免问题。

2.4表的设计方法

我们了解完何为三大范式后,我们就要明白建表的流程了:

  1. 先从需求中得到类,类对应数据库中的实体。
  2. 实体在数据库中表现为一张一张的表。
  3. 类的属性对应表中多个字段。
  4. 确定类与类之间的关系。

确定类与类之间的关系很重要,类之间的关系有以下几种:

  1. 一对一的关系,例如一个学生对应一个学校
  2. 一对多的关系,一个班级包含许多个学生
  3. 多对多的关系,例如一个学生可以选修许多学科,某个学科也可以被许多学生选择。

讲完了三大范式与设计方法,接下来来一段实操应用一下:

背景:创建数张表,用于存储课程信息,学生信息,以及学生成绩信息。

代码:

sql 复制代码
create table student_message(
st_id bigint PRIMARY KEY auto_increment,
name varchar(20) not NULL
);

CREATE table subject(
su_id BIGINT PRIMARY KEY auto_increment,
name varchar(20) not null
);

CREATE table score(
score_id BIGINT PRIMARY KEY auto_increment,
student_id BIGINT,
subject_id BIGINT,
grade bigint,
foreign key (student_id) REFERENCES student_message (st_id),
foreign key (subject_id) REFERENCES subject (su_id)
);

查询这三张表的语句:

sql 复制代码
select * from score;
select * from student_message;
select * from subject;

我们尝试插入一些数据看看效果如何:

sql 复制代码
INSERT into student_message values(1,'alice');
INSERT into student_message values(2,'tom');
INSERT into student_message values(3,'jerry');

insert into subject (su_id,name) values(1,'math'),(2,'english'),(3,'chinese');

insert into score values (1,1,1,90);
insert into score values (2,2,2,80);
insert into score values (4,2,3,95);

再次查询,结果如下:

分析一下结果:

其中多对多 关系,通过中间表(score 表)实现:

  • 学生(student_message) 与 科目(subject) 之间是多对多关系。
    • 一个学生可以选修多门科目。
    • 一门科目可以被多个学生选修。
  • score 表 是关系的桥梁,记录了某个学生在某门科目上的成绩。

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!

相关推荐
建投数据22 分钟前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi1 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀1 小时前
Redis梳理
数据库·redis·缓存
独行soc1 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天2 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺2 小时前
分布式系统架构:服务容错
数据库·架构
独行soc3 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍08-基于时间延迟的SQL注入(Time-Based SQL Injection)
数据库·sql·安全·渗透测试·漏洞挖掘
White_Mountain3 小时前
在Ubuntu中配置mysql,并允许外部访问数据库
数据库·mysql·ubuntu
Code apprenticeship3 小时前
怎么利用Redis实现延时队列?
数据库·redis·缓存
百度智能云技术站4 小时前
广告投放系统成本降低 70%+,基于 Redis 容量型数据库 PegaDB 的方案设计和业务实践
数据库·redis·oracle