关系范式
写在前面
引入
- 数据库的设计范式是数据库设计所需要满足的规范,满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。
参考
概念(默认已经了解)
主键(主属性、关键字、码...)、候选键(候选码)、非主属性
后面可能会混用称呼,意会即可。
- 函数依赖:部份依赖、完全依赖、传递依赖
- 数据冗余、更新异常、插入异常、删除异常
1NF
定义:如果数据表的所有属性都是 不可分 的基本数据项,则符合 1NF。
数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。
不满足第一范式就不是关系型数据库!
很显然,在当前的任何关系数据库管理系统(RDBMS,Relational Database Management System)中,天才也不能做出不符合第一范式的数据库。因为这些 RDBMS 不允许你把数据库表的一列再分成二列乃至多列,所以想在现有的 RDBMS 中设计出不符合第一范式的数据库是不可能的。
2NF
- 定义:在 1NF 的基础上,数据表每一个非主属性都 完全函数依赖 于主属性,则符合 2NF。
解释:
- 表中的属性必须依赖于全部主键,而不是部分主键,也即转化为 2NF 就是消除属性对主属性的部分依赖。
- 另外,所有单关键字的数据库表都符合 2NF,因为不可能存在组合关键字。
- 案例:选课关系表
SelectCourse
(学号
,姓名
,年龄
,课程名称
,成绩
,学分
),关键字为组合关键字 (学号
,课程名称
)。 分析:这个数据库表符合 1NF 的,但是不符合 2NF。
- 因为存在如下决定关系:(
课程名称
) → (学分
);(学号
) → (姓名
,年龄
)。存在非主属性部分依赖于主属性,或者说存在主关键字中的字段决定非关键字的情况。
- 因为存在如下决定关系:(
异常情况:由于不符合 2NF,这个
SelectCourse
会存在如下问题:- 数据冗余:同一门课程由 n 个学生选修,
学分
就重复 n - 1 次;同一个学生选修了 m 门课程,姓名
和年龄
就重复了 m - 1 次。 - 更新异常:若调整了某门课程的学分,表中所有对应
课程名称
元组的学分
属性都要同步更新,否则会出现同一门课程学分不同的情况。 - 插入异常:假设要开设一门新的课程,暂时还没有人选修。由于还没有
学号
关键字,课程名称
和学分
也无法记录入数据库。 - 删除异常:假设一批学生已经完成课程的选修,这些选修记录就应该从表中删除。但是与此同时
课程名称
和学分
信息也被删除了。很显然这也会导致插入异常。
- 数据冗余:同一门课程由 n 个学生选修,
改造:
把
SelectCourse
改为如下三个表:- 学生:
Student
(学号
,姓名
,年龄
) - 课程:
Course
(课程名称
,学分
) - 选课关系:
SelectCourse
(学号
,课程名称
,成绩
)
- 学生:
- 这样的数据库表是符合 2NF 的,消除了数据冗余、更新异常、插入异常和删除异常。
3NF
- 定义:在 2NF 的基础上,数据表中如果不存在非关键字段对任一候选关键字段的 传递函数依赖 则符合 3NF。
- 案例:学生关系表
Student
(学号
,姓名
,年龄
,所在学院
,学院地点
,学院电话
),关键字为单一关键字学号
。 分析:这个数据库表是符合 2NF 的,但是不符合 3NF。
- 因为存在如下决定关系: (
学号
) → (所在学院
) → (学院地点
,学院电话
)。即存在非关键字段学院地点
、学院电话
对关键字段学号
的传递函数依赖。
- 因为存在如下决定关系: (
异常情况:存在数据冗余、更新异常、插入异常和删除异常的情况。
- 数据冗余:同一个院校有 n 个学生,那么
学院地点
和学院电话
就重复存储了 n-1 次。 - 更新异常:若更改了某个学院的地点,表中所有对应
所在学院
元组的学院地点
属性都要同步更新,否则就会出现不一致的情况。 - 插入异常:如果某个新的学院里没有学生,那么就无法将该学院插入数据库。
- 删除异常:如果删除了一个学院的所有学生,那么该学院也将被删除掉。
- 数据冗余:同一个院校有 n 个学生,那么
改造:
把
Student
分为如下两个表:- 学生:
Student
(学号
,姓名
,年龄
,所在学院
) - 学院:
College
(学院
,地点
,电话
)
- 学生:
- 这样的数据库表是符合 3NF 的,消除了数据冗余、更新异常、插入异常和删除异常。
BCNF
- 定义:在 3NF 的基础上,数据库表中如果 不存在任何字段 对任一候选关键字段的传递函数依赖则符合 BCNF。
- 解释:3NF 已经消除了非关键字段对任一候选关键字段的传递函数依赖,那么到 BCNF 就只需要消除 候选关键字段之间 的传递函数依赖即可。
案例:
- 仓库管理关系表
StorehouseManage
(仓库 ID
,存储物品 ID
,管理员 ID
,数量
),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。
- 仓库管理关系表
分析:这个数据库表是符合 3NF 的,但是不符合 BCNF。
这个数据库表中存在如下决定关系:
- (
仓库 ID
,存储物品 ID
) → (管理员 ID
,数量
) - (
管理员 ID
,存储物品 ID
) → (仓库 ID
,数量
)
- (
- 所以 (
仓库 ID
,存储物品 ID
) 和 (管理员 ID
,存储物品 ID
) 都是StorehouseManage
的候选关键字,表中的唯一非关键字段为数量
,它是符合 3NF 的。 但是由于存在如下决定关系:
- (
仓库 ID
) → (管理员 ID
) - (
管理员 ID
) → (仓库 ID
)
- (
- 即存在关键字段决定关键字段的情况,所以其不符合 BCNF。
异常情况:存在数据冗余、更新异常、插入异常和删除异常的情况。
- 数据冗余:一个仓库存储 n 种物品,则
仓库 ID
与管理员 ID
重复存储了 n - 1 次。 - 更新异常:如果仓库换了管理员,则所有对应
仓库 ID
元组的管理员 ID
属性都要同步更新,否则出现数据不一致。 - 插入异常:如果新建了一个仓库,但是它没有存储物资,那么就无法插入数据库。
- 删除异常:如果一个仓库下存储的物资都被删除了,那么仓库也将被删除掉。
- 数据冗余:一个仓库存储 n 种物品,则
改造:
把
StorehouseManage
分解为两个关系表:- 仓库管理:
StorehouseManage
(仓库 ID
,管理员 ID
) - 仓库:
Storehouse
(仓库 ID
,存储物品 ID
,数量
)
- 仓库管理:
- 这样的数据库表是符合 BCNF 的,消除了删除异常、插入异常和更新异常。
再举一例:表 (
学生
,教师
,课程
),规定每位教师只开一门课,那么存在如下决定关系:- (
学生
,教师
) → U (学生
,教师
,课程
) - (
学生
,课程
) → U (学生
,教师
,课程
) 教师
→课程
课程
→教师
- 存在关键字段决定关键字段的情况,所以不符合 BCNF。
- (