数据库设计之三范式
1NF
、2NF
、3NF
第一范式:数据库中的每一列必须是不可拆分的最小单元,满足每一列的原子性。
上图表的设计明显不符合第一范式,因为列下面又出现了复合列,破坏了数据库中的每一列都必须不可拆分的最小单元的原则。实际上在现有的Relational DBMS
中,这种结构的表也是创建不出来的,关系型数据库不允许把数据库表的一列再分成两列或者多列,所以在关系型数据库中创建的表均满足最基础的第一范式。
创建:
id | region |
---|---|
1 | 中国上海市 |
2 | 中国浙江省 |
3 | 加拿大魁北克省 |
如果业务需要的话,则region
还可以继续拆分为:country
和province
id | country | province |
---|---|---|
1 | 中国 | 上海市 |
2 | 中国 | 浙江省 |
3 | 加拿大 | 魁北克省 |
第二范式:属性完全依赖于主键,消除部分子函数依赖。
简而言之,第二范式(2NF
)就是非主属性完全依赖于主键。
第二范式要求数据库表中的每一行都可以被唯一区分!为实现区分通常要为表添加一唯一属性列,用来存储每一行的唯一标识。此唯一属性列被称为主关键字、主键或主码。
选课表:select_cource(学号、学生姓名、学生年龄、课程名称、成绩、课程学分值)
student_no | student_name | student_age | cource_name | cource_score | cource_credits |
---|
一个学生可以选多门课,一门课可以对应多个学生,所以此表中唯一确定每一行的主键应为:(学号,课程名称)组合关键字。
存在如下关系:
(学号,课程名称)➡(学生姓名、学生年龄、成绩、学分)
这个数据库表不满足第二范式,因为:
(学号)➡(学生姓名、学生年龄)
(课程名称)➡(课程学分值)
即存在组合关键字中的字段决定非关键字的情况。
不符合第二范式的话,会出现如下问题:
1. 数据冗余:
同一门课程,比如高数,可以被n
个学生选修,高数课的学分大学里一般都是5
个学分,则表中“学分”字段就会重复n-1
次;同一个学生选修了m
门课程,则“学生姓名”和“年龄”就重复了m-1
次。
student_no | student_name | student_age | cource_name | cource_score | cource_credits |
---|---|---|---|---|---|
1 | 张三 | 22 | 高等数学 | 90 | 5 |
2 | 李四 | 23 | 大学物理 | 85 | 3 |
3 | 王五 | 22 | 高等数学 | 70 | 5 |
1 | 张三 | 22 | 数据结构 | 88 | 4 |
1 | 张三 | 22 | 线性代数 | 77 | 2 |
2. 更新异常:
若调整某门课程(如高数)的课程学分值,数据表中所有行的“学分”都要更新,否则出现同一门课程学分值不同的情况。
student_no | student_name | student_age | cource_name | cource_score | cource_credits |
---|---|---|---|---|---|
1 | 张三 | 22 | 高等数学 | 90 |
|
2 | 李四 | 23 | 大学物理 | 85 | 3 |
3 | 王五 | 22 | 高等数学 | 70 |
|
1 | 张三 | 22 | 数据结构 | 88 | 4 |
1 | 张三 | 22 | 线性代数 | 77 | 2 |
3. 插入异常:
假设要开设一门新的课程,暂时还没有学生选修此课程。由于没有“学号”关键字,则学生姓名、成绩和年龄无法记录数据库中。
student_no | student_name | student_age | cource_name | cource_score | cource_credits |
---|---|---|---|---|---|
1 | 张三 | 22 | 高等数学 | 90 | 5 |
2 | 李四 | 23 | 大学物理 | 85 | 3 |
3 | 王五 | 22 | 高等数学 | 70 | 5 |
1 | 张三 | 22 | 数据结构 | 88 | 4 |
1 | 张三 | 22 | 线性代数 | 77 | 2 |
NULL | NULL | NULL | 大学英语 | NULL | 3 |
4. 删除异常:
假设一批学生已经完成课程的选修,这些选修记录就应该从数据库中删除。但是,与此同时,课程名称和课程学分值也被删除了。
student_no | student_name | student_age | cource_name | cource_score | cource_credits |
---|---|---|---|---|---|
1 | 张三 | 22 | 高等数学 | 90 | 5 |
2 | 李四 | 23 | 大学物理 | 85 | 3 |
3 | 王五 | 22 | 高等数学 | 70 | 5 |
1 | 张三 | 22 | 数据结构 | 88 | 4 |
1 | 张三 | 22 | 线性代数 | 77 | 2 |
若上表中记录是2012
级学生选课记录,学期结束时,如果需要清除数据,则直接将表中数据全部清除了,但是,高等数学、大学物理、数据结构、线性代数等这些课程2013
级新同学还是要选修的,此时已经删除了,没得选了。
5. 重新设计表:
student(学号、学生姓名、学生年龄)
cource(课程名称、课程学分值)
select_cource(学号、课程名称、成绩)
6. 另外,所有单主键的数据库表都符合第二范式,因为它的主键不是组合字段。
第三范式:属性不依赖于其他非主属性,消除传递依赖
第三范式要求一个数据库表中不包含其他表中已包含的非主键信息。
第三范式消除了数据冗余、插入异常、更新异常、删除异常。
例如:部门信息表:dept_info
dept_id | dept_name | dept_description |
---|---|---|
1 | 财务部 | 负责公司财务 |
2 | 技术部 | 负责产品技术开发 |
3 | 运营部 | 负责业务运营 |
员工表:employee
,employee
表中列出员工所属部门编号之外,部门名称、部门描述等字段就不能再加入employee
表中。如果不存在dept_info
表,则根据第三范式,应该构建它,否则就会有大量的数据冗余。
emp_id | emp_name | dept_id | |
---|---|---|---|
1 | 张三 | 2 | |
2 | 李四 | 3 | |
3 | 王五 | 3 | |
4 | 香克斯 | 1 |
上一篇: java进阶|MySQL数据库系列(四)查询操作和多表关联查询
下一篇: 范式理论的程序设计(五)