这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
- 1NF:所有字段仅包含单值(即单个字段不可在分割使用)
- 2NF:非键字段必须全完依赖于主键(不能是主键的部分)
- 3NF:非键字段不能依赖于非键字段(禁止传递依赖)
- BCNF:并且主属性不依赖于主属性
- 第四范式(4NF) :要求把同一表内的多对多关系删除
- 第五范式(5NF) :从最终结构重新建立原始结构
四种范式之间的关系:
1NF→2NF:消去非主属性对键的部分函数依赖
2NF→3NF:消去非主属性对键的传递函数依赖
3NF→BCNF:消去主属性对键的传递函数依赖
1 第一范式(1NF)
列都是不可再分。即实体中的某个属性有多个值时,必须拆分为不同的属性。例如:
用户信息表
编号 | 姓名 | 年龄 | 地址 |
---|---|---|---|
1 | 小王 | 23 | 浙江省杭州市拱墅区湖州街51号 |
当实际需求对地址没有特定的要求下,这个用户信息表的每一列都是不可分割的。但是当实际需求对省份或者城市有特别要求时,这个用户信息表中的地址就是可以分割的,改为:
用户信息表
编号 | 姓名 | 年龄 | 省份 | 城市 | 详细地址 |
---|---|---|---|---|---|
1 | 小王 | 23 | 浙江省 | 杭州市 | 拱墅区湖州街51号 |
好处
- 表结构相对清晰
- 易于查询
2 第二范式(2NF)
每个表只描述一件事情。满足第一范式( 1NF)的情况下,每行必须有主键,且主键与非主键之间是完全函数依赖关系(消除部分子函数依赖)。即数据库表中的每一列都和主键的所有属性相关,不能只和主键的部分属性相关。完全函数依赖:有属性集 X,Y,通过 X 中的所有属性能够推出 Y 中的任意属性,但是 X 的任何真子集,都不能推出 Y 中的任何属性。例如:
学生课程表
学生编号 | 课程编号 | 学生名称 | 课程名称 | 所在班级 | 班主任 |
---|---|---|---|---|---|
S1 | C1 | 小王 | 计算机导论 | 计算机3班 | 陈老师 |
S1 | C2 | 小王 | 数据结构 | 计算机3班 | 陈老师 |
S2 | C1 | 小马 | 计算机导论 | 软件1班 | 李老师 |
将学生编号和课程编号作为主键,能确定唯一一条数据,但是学生名称只跟学生编号有关,跟课程编号无关,即不满足完全函数依赖,改为:
学生表
学生编号 | 学生名称 | 所在班级 | 班主任 |
---|---|---|---|
S1 | 小王 | 计算机3班 | 陈老师 |
S2 | 小马 | 软件1班 | 李老师 |
课程表
课程编号 | 课程名称 |
---|---|
C1 | 计算机导论 |
C2 | 数据结构 |
学生课程关系表
学生编号 | 课程编号 |
---|---|
S1 | C1 |
S1 | C2 |
S2 | C1 |
好处
- 相对节约空间,当学生表和课程表属性越多,效果越明显
- 解决插入异常,当新增一门课程时,原表因为没有学生选课,导致无法插入数据
- 解决更新繁琐,当更改一门课程名称时,原表要更改多条数据
- 解决删除异常,当学生学完一门课,原表若要清空学生上课信息,课程编号与课程名称的关系可能会丢失
3 第三范式(3NF)
不存在对非主键列的传递依赖。满足第二范式( 2NF)的情况下,任何非主属性不依赖于其它非主属性(消除传递函数依赖)。例如:
学生表
学生编号 | 学生名称 | 班级编号 | 班级名字 |
---|---|---|---|
S1 | 小王 | 001 | 计算机1班 |
S2 | 小马 | 003 | 计算机3班 |
学生编号作为主键满足第二范式(2NF)。通过学生编号 ⇒⇒ 班级编号 ⇒⇒ 班级名字,所以班级编号和班级名字之间存在依赖关系,改为:
学生表
学生编号 | 学生名称 | 班级编号 |
---|---|---|
S1 | 小王 | 001 |
S2 | 小马 | 003 |
班级表
班级编号 | 班级名称 |
---|---|
001 | 计算机1班 |
003 | 计算机3班 |
好处
- 相对节约空间
- 解决更新繁琐
- 解决插入异常,当班级分配了老师,还没分配学生的时候,原表将不可插入数据
- 解决删除异常,当学生毕业后,若要清空学生信息,班级和老师的关系可能会丢失
4 巴斯-科德范式(BCNF)
在3NF基础上,消除主属性之间的传递函数依赖,即存在多个主属性时,主属性不依赖于主属性。例如: 配件表
仓库号 | 配件号 | 职工号 | 配件数量 |
---|---|---|---|
W1 | P1 | E1 | 10 |
W1 | P2 | E1 | 10 |
W2 | P1 | E2 | 20 |
有以下约束:
- 一个仓库有多个职工
- 一个职工只在一个仓库
- 一种配件可以放多个仓库
- 一个仓库,一个职工管理多个配件,一种配件由唯一一个职工管理
由此,将(仓库号,配件号)作为主键,满足 3NF,但是(仓库号,配件号)⇒⇒ 职工号 ⇒⇒ 仓库号,造成传递函数依赖,改为:
仓库表
仓库号 | 职工号 |
---|---|
W1 | E1 |
W2 | E2 |
工作表
职工号 | 配件号 | 配件数量 |
---|---|---|
E1 | P1 | 10 |
E1 | P2 | 10 |
E2 | P1 | 20 |
好处
- 解决一些冗余和一些异常情况
不足
- 丢失一些函数依赖,如丢失(仓库号,配件号)⇒⇒ 职工号,无法通过单表来确定一个职工号
5 第四范式(4NF)
在满足第三范式(3NF)的前提下,表中不能包含一个实体的两个或多个互相独立的多值因子。
当一个表中非主属性相互独立时(即在 3NF 基础上),这些非主属性不应该有多值
。即表中不能包含一个实体的两个或多个互相独立的多值因子。例如:
客户联系方式
客户编号 | 固定电话 | 移动电话 |
---|---|---|
10 | 88-123 | 151 |
10 | 80-123 | 183 |
一个用户拥有多个固定电话和移动电话,给表的维护带来很多麻烦。比如增加一个固定电话,那么移动电话这一栏就较难维护,改为:
客户电话表
客户编号 | 电话号码 | 电话类型 |
---|---|---|
10 | 88-123 | 固定电话 |
10 | 80-123 | 固定电话 |
10 | 151 | 移动电话 |
10 | 183 | 移动电话 |
好处
- 解决一些异常,使表结构更加合理
6 第五范式(5NF)
在关系模式 R 中,每一个连接依赖
均有 R 的候选码
所隐含。即连接时,所连接的属性都是候选码,例如:
销售表
销售人员 | 供应商 | 产品 |
---|---|---|
S1 | V1 | P1 |
S2 | V2 | P2 |
S1 | V1 | P1 |
S2 | V2 | P2 |
要想找到某一条数据,必须以(销售人员,供应商,产品)为主键,改为:
销售人员_供应商表
销售人员 | 供应商 |
---|---|
S1 | V1 |
S2 | V2 |
销售人员_产品表
销售人员 | 产品 |
---|---|
S1 | P1 |
S2 | P2 |
供应商_产品表
供应商 | 产品 |
---|---|
V1 | P1 |
V2 | P2 |
好处
- 解决某些异常操作