题目
数据库三范式
答案
@[toc]
---
数据库三范式是关系数据库的设计原则,它帮助我们规划出结构合理、稳定性好的关系型数据库
## 第一范式(1NF):确保每列都是不可拆分的
这意味着每一列的值都不能再分解成更小的值。
比如一张学生表 Students,包含字段(学号,姓名,性别,出生年月日)
| Id(学号) | Name(姓名) | Sex(性别) | Birth(出生日期) |
| ---------- | ------------ | ----------- | ----------------- |
| 1 | 小牛肉 | 男 | 2023-05-01 |
如果出生日期在业务中还需要再分成(出生年,出生月,出生日),那么这个设计就不符合第一范式。
## 第二范式(2NF):在第一范式的基础上,确保非主键列完全依赖于主键,而不是依赖于主键的一部分
这意味着非主键列必须依赖于完整的主键,而不是依赖于主键的一部分。
比如一张选课表 StudentCourse,包含字段(学号、课程号、姓名、学分),**学号和课程号是主键**,唯一确定一行记录:
| 学号 | 课程号 | 姓名 | 学分 |
| ---- | ------ | ------ | ---- |
| 1 | 18 | 小牛肉 | 4.0 |
这个表显然说明了两段信息:
- 学生信息(学号,姓名)
- 课程信息(课程号,学分)
学分依赖于学号和课程号,完全依赖于主键;但是很显然学生姓名只需要依赖于学号,不依赖于课程号,即部分依赖于主键,所以不满足第二范式。
如果不满足第二范式,那么**可能会存在下述问题**:
- `数据冗余`:每条记录都含有相同信息。比如学号 = 1 的学生选了课程号 18 和 20 的课程,那么这张表中学号 1 和姓名 “小牛肉” 就会出现 2 次:
| 学号 | 课程号 | 姓名 | 学分 |
| ---- | ------ | ------ | ---- |
| 1 | 18 | 小牛肉 | 4.0 |
| 1 | 20 | 小牛肉 | 2.0 |
- `删除异常`:删除所有学生成绩,就会把课程信息(课程号,学分)全删除了
- `插入异常`:如果学生未选课,则无法将学生信息存入数据库
- `更新异常`:如果需要调整某门课程的学分,那么所有涉及到这门课程的记录都需要进行调整
上述示例满足第二范式的设计应该是:
- 学生表:`Student` (学号, 姓名),主键是学号
- 课程表:`Course` (课程号, 学分),主键是课程号
- 成绩表:`StudentCourse`(学号, 课程号, 成绩),主键是学号和课程号
## 第三范式(3NF):在第二范式的基础上,确保非主键列不存在传递依赖
如果一个关系满足第二范式,并且**在两个 (或多个) 非主键属性之间不存在函数依赖** (非主键属性之间的函数依赖也称为传递依赖),那么这个关系就满足第三范式。
> 举个例子,一张表中有 A B C 三个字段,B 依赖于 A(A→B),C 依赖于 B(B→C),那么则称 C 传递依赖于 A(A→C)
简单来说,**3NF 要求任何字段不能由其他字段派生出来,它要求字段没有冗余,即不存在传递依赖**。
比如一张学生信息表,包含字段(学号、姓名、年龄、学院编号、学院名称、学院电话),**学号是主键**,唯一确定一行记录:
| 学号 | 姓名 | 年龄 | 学院编号 | 学院名称 | 学院电话 |
| ---- | ------ | ---- | -------- | ---------- | -------- |
| 1 | 小牛肉 | 18 | 111 | 计算机学院 | 12345 |
这个表显然说明了两段信息:
- 学生信息(学号、姓名、年龄)
- 学院信息(学院编号、学院名称、学院电话)
每一行记录中的学院编号都依赖于学号(学号→学院编号),而学院名称依赖于学院编号(学院编号→学院名称),即学院名称传递依赖于学号(学号→学院名称)
如果不满足第三范式,**可能会存在下述问题**:
- `数据冗余`
- `更新异常`
上述示例满足第二范式的设计应该是:
- 学生信息(学号、姓名、年龄、学院编号):主键是学号
- 学院信息(学院编号、学院名称、学院电话):主键是学院编号
