1.第一范式(1NF)
2.第二范式(2NF)
以学生选课为例,每个学生都可以选课,并且有这一门课程的成绩,那么如果将这些信息都放在一张表StuGrade(stuNo,stuName,age,sex,courseNo,courseName,credit,score)。
如果不仔细看,我们会以为这张表的主键是stuNo,但是当我们看到最后一个score属性以后,在想想如果没有课程信息,那么哪里有学生成绩信息呢。所以这张表的主键是一个联合主键(stuNo,corseNo),这个联合属性能够唯一确定score属性。那么再看其他信息,比如stuName只需要stuNo就能够唯一确定,courseName只需要courseNo就能够唯一确定,因此这样就存在了部分依赖,不符合第二范式。如果要让学生课程成绩信息满足第二范式,那么久需要将这张表拆分成多张表,一张学生表Studnet(stuNo,stuName,age,sex),一张课程表Course(courseNo,courseName,credit),还有最后一张学生课程成绩表StuGrade(stuNo,courseNo,score)。这样就符合第二范式了。
3.第三范式(3NF)
这张员工信息表的主键是emp_id,因为这个属性能够唯一确定其他所有属性,比如知道员工编号emp_id以后,肯定能够知道员工姓名,所属部门编号,部门名称和部门介绍。所以这里dept_id不是主属性,而是非主属性。但是,我们又可以发现dept_name,dept_info这两个属性也可以由dept_id这个非主属性决定,即dept_name依赖dept_id,而dept_id依赖emp_id,这样就存在了传递依赖。而且我们可以看出传递依赖的一个明显缺点就是数据冗余非常严重。
那么如何解决传递依赖问题,其实非常简单,我们只需要将dept_name,dept_info这连个属性删除就可以了,即Employee(emp_id,emp_name,emp_age,dept_id),然后再创建一个部门表Dept(dept_id,dept_name,dept_info)。
这样如果要搜索某一个员工的部门信息dept_info,可以通过数据库连接来实现,查询语句如下:
select e.emp_id,e.emp_name,d.dept_name from Employee e,Dept d where e.dept_id=d.dept_id
4.BCNF范式(BCNF)
如何理解?
假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:
(仓库ID, 存储物品ID) →(管理员ID, 数量)
(管理员ID, 存储物品ID) → (仓库ID, 数量)
所以,(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:
(仓库ID) → (管理员ID)
(管理员ID) → (仓库ID)
即存在关键字段决定关键字段的情况,所以其不符合BCNF范式。它会出现如下异常情况:
(1) 删除异常:当仓库被清空后,所有”存储物品ID”和”数量”信息被删除的同时,”仓库ID”和”管理员ID”信息也被删除了。
(2) 插入异常:当仓库没有存储任何物品时,无法给仓库分配管理员。
(3) 更新异常:如果仓库换了管理员,则表中所有行的管理员ID都要修改。
把仓库管理关系表分解为二个关系表:
仓库管理:StorehouseManage(仓库ID, 管理员ID);
仓库:Storehouse(仓库ID, 存储物品ID, 数量)。
这样的数据库表是符合BCNF范式的,消除了删除异常、插入异常和更新异常。
评论