各种函数依赖及规范化解决

假设我们有一个表格存储学生成绩信息:

学生成绩表

学号 (SNo)课程号 (CNo)分数 (Score)姓名 (Name)班级 (Class)

1. 函数依赖分类

前提:X——>Y(即X决定Y)

1.1 分类1:平凡/非平凡依赖

依据‌:依赖关系中Y是否为X的子集。即基于属性集的包含关系Y是否属于X

  • ‌平凡函数依赖‌:若Y⊆X,则X→Y为平凡函数依赖‌。例如关系模式(学号,姓名,年级)中,(学号,姓名)→姓名属于平凡依赖,因“姓名”是属性组(学号,姓名)的子集‌
  • ‌非平凡函数依赖‌:若X→Y且Y∉X,则为非平凡依赖‌。例如学号→年级,因“年级”不包含于“学号”这一属性‌

1. 平凡依赖(Trivial Dependency)

平凡依赖指的是属性集中的某个属性依赖于自身。不需要从其他属性获得信息。

例子:

  • 在表中,对于任何属性集 {SNo, CNo, Score},平凡依赖有 {SNo} → SNo, {CNo, Score} → Score 等。

2. 非平凡依赖(Non-Trivial Dependency)

非平凡依赖是指如果 X → Y 成立并且 Y 不属于 X,这称为非平凡依赖。

例子:

  • 在学生成绩表中,{SNo, CNo} → Score 是一个非平凡依赖,因为分数 Score 不属于组合键 {SNo, CNo}。

1.2 分类2:完全/部分(传递)依赖

依据‌:依赖关系中X的真子集是否决定Y,或是否通过中间属性间接决定。 即 基于依赖的完整性是否需全部属性或传递性是否通过中间属性)‌

  • ‌完全函数依赖‌:Y完全依赖于X,当且仅当X的任意真子集均无法决定Y‌。例如(学号,课程号)→成绩,因单独学号或课程号均无法确定成绩‌
  • ‌部分函数依赖‌:Y部分依赖于X,若存在X的真子集X'能决定Y‌。例如(学号,课程号)→姓名,因仅“学号”即可决定“姓名”,无需组合属性‌
  • ‌传递函数依赖‌:通过中间属性间接依赖,即X→Y,Y→Z,但Y↛X,则X→Z为传递依赖‌。例如学号→系名,系名→系主任,则学号→系主任为传递依赖‌

1. 完全函数依赖(Full Functional Dependency)

完全函数依赖是指 Y 对 X 是完全依赖的,但对 X 的任何真子集都不依赖,即去掉任何一个 X 的成分,依赖关系不再成立。

例子:

  • {SNo, CNo} → Score 是完全函数依赖,因为只有通过学号和课程号的组合才能唯一确定一个分数。

2. 部分函数依赖(Partial Functional Dependency)

部分函数依赖指的是在一个复合主键中,如果有一个非主属性依赖于主键的一部分,而不是整个主键。

假设学生成绩表的主键是由“学号 (SNo)”和“课程号 (CNo)”组合而成,这样能唯一标识一条记录。

然而,“姓名 (Name)”和“班级 (Class)”只依赖于“学号 (SNo)”而非整个主键,因为一个学生会有多个课程。因此,这里有部分函数依赖:

  • 名称 (Name) 依赖于 学号 (SNo)
  • 班级 (Class) 依赖于 学号 (SNo)

3. 传递函数依赖(Transitive Dependency)

传递函数依赖是指如果存在 X → Y 和 Y → Z,那么就有 X → Z。通常在属性集合中隐含信息传递。

例子:

  • 假设我们有一个额外的表记录班级信息,比如班级代表:
 
  班级信息表
  | 班级 (Class) | 班长 (Leader) |
  |--------------|---------------|

在这种情况下,学生成绩表中的班级对班长存在传递函数依赖:{SNo} → {Class} 和 {Class} → {Leader},因此 {SNo} → {Leader} 是传递依赖。

这些不同类型的依赖关系帮助我们识别数据库设计中的冗余、异常,并指导我们进行范式化处理。

2. 规范化

2.1 不规范

不会发生插入异常、删除异常、更新异常,数据冗余应尽可能少。

https://fangkaipeng.com/?p=921

例:关系模式R中  (学生的学号(Sno)、所在系(Sdept)系主任姓名(Mname)、课程名(Cname)、成绩(Grade))

  • 数据冗余
    比如,每一个系的系主任姓名重复出现,重复次数与该系所有学生的所有课程成绩出现次数相同,如表6.1所示。这将浪费大量的存储空间。
    • 冗余的根本原因‌是‌存在部分函数依赖‌(非完全函数依赖):
      • 候选键为(Sno, Cname),但非主属性 Sdept 和 Mname ‌仅依赖于 Sno‌(候选键的真子集),而非完整的候选键‌23。
      • 即:Sno → Sdept → Mname,而(Sno, Cname)→ Sdept 是冗余的依赖路径‌
  • 更新异常(update anomalies)
    由于数据冗余,当更新数据库中的数据时,系统要付出很大的代价来维护数据库的完整性,否则会面临数据不一致的危险。比如,某系更换系主任后,必须修改与该系学生有关的每一个元组。
  • 插入异常(insertion anomalies)
    如果一个系刚成立,尚无学生,则无法把这个系及其系主任的信息存入数据库
  • 删除异常(deletion anomalies)
    如果某个系的学生全部毕业了,则在删除该系学生信息的同时,这个系及其系主任的信息也丢掉了。

上述的关系模式不是一个好的关系模式。这是由存在于模式中的某些数据依赖引起的,可以通过分解关系模式来消除其中不合适的数据依赖。

2.2 解决:规范化

1NF:

第一:属性 不可再分

(消除多值属性与重复字段)

2NF:

 

2NF:满足1NF,且 非主属性 完全依赖 主属性,而不是部分依赖(消除冗余更新异常)

 

将原关系 R 分解为以下两个表:

  1. ‌学生-系表(Student_Dept)‌:

    • 属性:Sno(学号)、Sdept(系)、Mname(系主任)

    • 候选键:Sno(完全函数依赖)

    • 依赖关系:Sno → Sdept → Mname‌

  2. ‌选课成绩表(SC)‌:
    • 属性:Sno(学号)、Cname(课程名)、Grade(成绩)
    • 候选键:(Sno, Cname)(完全函数依赖)
    • 依赖关系:(Sno, Cname)→ Grade‌

通过分解,原关系中的冗余数据和部分依赖被消除,满足第二范式要求‌

3NF

第三:满足第二,且消除传递依赖

(消除传递依赖导致的数据冗余)

BCNF 

BCNF:满足3NF,且对于每一个非平凡的函数依赖 X -> YX 必须是一个候选键,而不仅仅涉及主键(或候选键)的一部分。

示例1:

假设我们有一个表 Enrollments候选键(CourseID, ProfessorID),但是有依赖 CourseID -> ProfessorID违反BCNF

CourseIDProfessorIDStudentIDProfessorName
C001 P001 S001 Dr. Smith
C002 P002 S002 Dr. Johnson

假设 CourseID 是唯一的课程标识,所以 CourseID -> ProfessorID 是一个函数依赖。在这种情况下,ProfessorName 对 ProfessorID 和 CourseID 的依赖不是符合BCNF的,因为 ProfessorID 本身应该是一个候选键。

为使表进入BCNF,我们需要分解表:

  1. ProfessorDetails 表:
ProfessorIDProfessorName
P001 Dr. Smith
P002 Dr. Johnson
  1. Enrollments 表:
CourseIDProfessorIDStudentID
C001 P001 S001
C002 P002 S002

在这里,通过分解 we 能够消除 ProfessorName 的传递依赖,因为它直接从 ProfessorID 派生,而 ProfessorID 是一个候选键。

通过这些示例,我们可以看到,2NF 主要关注消除部分依赖,而 BCNF 关注任何情况下的函数依赖,确保候选键的充分利用。

示例2:

好的,让我们来看看一个符合第二范式 (2NF) 但是不符合 Boyce-Codd 范式 (BCNF) 的例子。

示例表:Assignments

假设我们有一个表 Assignments,其中:

  • 主键是组合键 (StudentID, AssignmentID)
  • 这些属性意味着每个学生可以有多个作业,每个作业可以由不同的课程指定。

假设表结构如下:

StudentIDAssignmentIDCourseIDCourseInstructor
S001 A001 C001 Dr. Smith
S002 A002 C002 Dr. Johnson
S001 A003 C001 Dr. Smith
S002 A004 C003 Dr. Williams

依赖关系:

  • 主键为 (StudentID, AssignmentID)
  • CourseID 和 CourseInstructor 是对 (StudentID, AssignmentID) 的完全依赖,因为它们由两个属性决定。
  • CourseID -> CourseInstructor 是一个非主属性到非主属性的依赖。

2NF 分析

该表已满足 1NF,因为所有属性均为原子值。
通过查看 (StudentID, AssignmentID) 的组合,我们看不到部分依赖。
因此,该表符合 2NF,因为所有非主属性都对整个主键而不是部分主键完全依赖。

BCNF 分析

BCNF 要求每个函数依赖具有候选键。

  • CourseID -> CourseInstructor 是一个非平凡的函数依赖,但 CourseID 不是候选键
    这个非平凡的依赖性违反了 BCNF 的要求,因为 CourseID 不是候选键。

分解到BCNF

为了使表达到 BCNF,我们可以通过将表分解为两个表:

  1. Courses 表:
CourseIDCourseInstructor
C001 Dr. Smith
C002 Dr. Johnson
C003 Dr. Williams
  1. Assignments 表:
StudentIDAssignmentIDCourseID
S001 A001 C001
S002 A002 C002
S001 A003 C001
S002 A004 C003

这样,CourseInstructor 直接依赖于候选键 CourseID,符合 BCNF 要求。在这种情况下,我们消除了非主键间的依赖关系,并确保所有非平凡的函数依赖都有一个候选键。

posted on 2024-10-15 17:03  gogoy  阅读(328)  评论(0)    收藏  举报

导航