本章的目的:如何构造一个好的数据库模式

6.1 问题的提出:

  • 关系模式的表示:
    • 关系模式由五部分组成,是一个五元组:R(U,D,DOM,F)
    • R表示关系模式名
    • U表示一组属性
    • D表示U的取值范围,如Son的取值范围是0-100
    • DOM表示属性的域映射,如age到整数100,中的映射
    • F为属性组U的组数据依赖,如函数依赖,多值依赖等等
  • 细节:
    • 由于D、DOM与模式设计关系不大,因此在本章把关系模式看作一个三元组:R
    • 当且仅当<span data-mathml="U”>U上的一个关系<span data-mathml="r”>r满足<span data-mathml="F”>F时,<span data-mathml="r”>r称为关系模式<span data-mathml="R”>R的一个关系
      • <span data-mathml="U”><span data-mathml="r”><span data-mathml="F”><span data-mathml="r”><span data-mathml="R”>理解:U是一组属性(如:学生表),如果有一个表里的数据满足U这一组属性(如:学生表),那么该表就是模式里的一个关系  
    • 作为二维表,关系要符合一个最基本的条件:每个分量必须是不可分的数据项。满足了这个条件的关系模式就属于第一范式(1NF)
      • 理解:
  • 数据依赖:

    • 一个关系内部属性与属性之间的一种约束关系,通过属性间值的相等与否体现出来的数据间相关联系      

  • 数据依赖的主要类型:
    • 函数依赖(简记:FD)
      • 理解:如:知道学生学号,推出学生姓名,知道学生选课号,推出课程名称  
    • 多值依赖(简记:MVD)
      • 理解:如:和函数一样,但它可以通过一个值推出多个数据
  • 函数依赖在现实生活中的体现:
    • 例1:描述一个学生关系,可以有学号、姓名、系名等属性 
    • 一个学号只对应一个学生,一个学生只在一个系中学习,“学号”值确定后,学生的姓名及所在系的值就被唯一确定
    • Sname=f(Sno),Sdept=f(Sno) 就即Sno函数决定Sname,Sno函数决定Sdept,记作Sno -> Sname,Sno->Sdpt 
    • 例2:建立一个描述学校教务的数据库,涉及的对象包括:学生的学号(<span data-mathml="Sno”>Sno)、所在系(<span data-mathml="Sdept”>Sdept)、系主任姓名(<span data-mathml="Mname”>Mname)、课程号(<span data-mathml="Cno”>Cno)、成绩(<span data-mathml="Grade”>Grade)
    • <span data-mathml="Sno”><span data-mathml="Sdept”><span data-mathml="Mname”><span data-mathml="Cno”><span data-mathml="Grade”>假设学校教务的数据库模式用一个单一的关系模式 Student 来表示,则该关系模式的属性集合为:U = {Sno,Sdept,Mname,Cno,Crade} 
    • 现实世界的已知事实(语义):
      • ① 一个系有若干学生,但一个学生只属于一个系

        ② 一个系只有一名(正职)负责人

        ③ 一个学生可以选修多门课程,每门课程有若干学生选修

        ④ 每个学生学习每一门课程有一个成绩

    • 由此可得到属性组<span data-mathml="U”>U上的一组函数依赖<span data-mathml="F”>F:F = {Sno -> Sdept, Sdept -> Mname, (Sno,Cno) -> Grade}

    • <span data-mathml="U”><span data-mathml="F”>

  • 函数依赖存在的问题:

    • 数据冗余:上述例子中,如果一个学生选择了10本课程,那么系主任的名字就重复10次,就产生了数据冗余

    • 更新异常:数据冗余,更新数据时,维护数据完整性代价大。如,系更换系主任后,必须修改与该系学生有关的每一个元组

    • 插入异常:如果一个系刚成立,尚无学生,则无法把这个系及其系主任的信息存入数据库,因:学号是主码,课程号是主码,为空那么主任的信息就不能插入

    • 删除异常:如果某个系的学生全部毕业了,则在删除该系学生信息的同时,这个系及其系主任的信息也丢掉了,因主码不能为空,为空了信息怎么还存在

  • 说明: 

    • 上述的Student关系模式不是一个好的模式,一个“好”的模式应当不会发生插入异常、删除异常和更新异常,数据冗余应尽可能少

      • 存在以上问题的原因是这个模式中的函数依赖存在某些不好的性质

    • 解决方法:用规范化理论改造关系模式来消除其中不合适的函数依赖 

  • 函数依赖的解决方式:

    • 用规范化理论改造关系模式来消除其中不合适的函数依赖,就是尽可能的去减少一个表中的多个函数依赖

    • S(Sno,Sdept,Sno -> Sdept)

    • SC(Sno,Cno,Grade,(Sno,Cno) -> Grade)

    • DEPT(Sdept,Mname,Sdept -> Mname)  

    • 这三个模式都不会发生插入异常、删除异常的问题,数据的冗余也得到了控制

6.2 规范化:

  • 什么是规范化?如何把不好的数据库(各种函数依赖,数据冗余,更新异常,插入异常删除异常)的数据规范化

6.2.1 函数依赖:

  • 什么是函数依赖?如:学号确定姓名,姓名确定学号,但不能一个学号确定多个姓名,一个姓名确定多个学号
  • 例:如果Sname是不能重名的
  • 有关函数的一些术语和记号:
  • 细节1:对于任一关系模式,平凡函数依赖都是必然成立的,它不反映新的语义。若不特别声明,总是讨论非平凡函数依赖
  • 细节2:x和y可以是一个,或者是一组
  • X -> Y,但<span data-mathml="Y⊈X”>Y⊈X,则称<span data-mathml="X→Y”>X→Y是非平凡的函数依赖
    • <span data-mathml="Y⊈X”><span data-mathml="X→Y”>理解:如(Sno,Sname) -> Grade, 那么Grade可以推出Sno或Sname吗?不能这就是<span data-mathml="Y⊈X”><span data-mathml="X→Y”>非平凡的函数依赖  
  • X -> Y,但<span data-mathml="Y⊆X”>Y⊆X,则称<span data-mathml="X→Y”>X→Y是平凡的函数依赖
    • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>理解:如(Sno,Sname) -> Sno,那么Sno 推出里面其中一个(Sno,Sname)就是<span data-mathml="Y⊆X”><span data-mathml="X→Y”>平凡的函数依赖
  • <span data-mathml="Y⊆X”><span data-mathml="X→Y”><span data-mathml="X→Y”>X→Y,则<span data-mathml="X”>X称为这个函数依赖的决定属性组,也称为决定因素
    • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>如:通过系名得到系主任的名字,那么系名就是决定因素
  • <span data-mathml="Y⊆X”><span data-mathml="X→Y”><span data-mathml="X→Y”>X→Y,<span data-mathml="Y→X”>Y→X,则记作<span data-mathml="X←→Y”>X←→Y
  • <span data-mathml="Y”>Y不函数依赖于<span data-mathml="X”>X,则记作<span data-mathml="X↛Y”>X Y<span data-mathml="Y⊆X”><span data-mathml="X→Y”> 
  • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>完全函数依赖:记作:<span data-mathml="X→FY”>XY<span data-mathml="Y⊆X”><span data-mathml="X→Y”><span data-mathml="X→FY”>
    • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>什么是完全函数依赖?如:(Sno,Sname) -> Grade,但是Grade推不出来Sno,Sname
    • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>课本原文:<span data-mathml="R(U)”>R(U)中,如果<span data-mathml="X→Y”>X→Y,并且对于<span data-mathml="X”>X的任何一个真子集<span data-mathml="X′”>X′, 都有<span data-mathml="X′↛Y”>X′↛Y, 则称<span data-mathml="Y”>Y对<span data-mathml="X”>X完全函数依赖<span data-mathml="Y⊆X”><span data-mathml="X→Y”>记作<span data-mathml="X→FY”>XY
  • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>部分函数依赖:记住:XY
    • <span data-mathml="Y⊆X”><span data-mathml="X→Y”><span data-mathml="Y⊆X”><span data-mathml="X→Y”>什么是<span data-mathml="Y⊆X”><span data-mathml="X→Y”>部分函数依赖?如:(Sno,Sname) -> sno或Sname,Sno可以推出(Sno,Sname)里的Sno
    • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>课本原文:若<span data-mathml="X→Y”>X→Y,但<span data-mathml="Y”>Y不完全函数依赖于<span data-mathml="X”>X,则称<span data-mathml="Y”>Y对<span data-mathml="X”>X部分函数依赖<span data-mathml="Y⊆X”><span data-mathml="X→Y”>记作<span data-mathml="Y⊆X”><span data-mathml="X→Y”>部分函数依赖:<span data-mathml="Y⊆X”><span data-mathml="X→Y”>记住XY
  • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>例子:
  • <span data-mathml="Y⊆X”><span data-mathml="X→Y”>
  • 传递函数依赖:记作:X<span data-mathml="X→传递Z”>Z

    • <span data-mathml="X→传递Z”>什么是传递函数依赖:如:(Sno) -> Sdept,Sdept->Mname,就是一个依赖于一个,学号知道系,系不能知道确定学号,系得到系主任

    • <span data-mathml="X→传递Z”>课本原文:在<span data-mathml="R(U)”>R(U)中,如果<span data-mathml="X→Y”>X→Y<span data-mathml="(Y⊈X)”>(Y⊈X),<span data-mathml="Y↛X”>Y↛X,<span data-mathml="Y→Z”>Y→Z,<span data-mathml="Z⊈Y”>Z⊈Y,则称<span data-mathml="Z”>Z对<span data-mathml="X”>X传递函数依赖(transitive functional dependency)。记为:X<span data-mathml="X→传递Z”>Z  

    • 细节:X和Y不能相互依赖XY,否则就是Z直接依赖于X,就不是传递依赖了

6.2.2 码:

  • 细节:码也称“键”或”键码”就是叫法不同性质一样
  • 候选码:
    • 什么是候选码?给定一个值可以确定一条记录,如学生表中的Sno或Sname(学生姓名不能重名),那么Sno和Sname就都是候选码
    • 课本原文:设<span data-mathml="K”>K为<span data-mathml="R”>R中的属性或属性组合。若<span data-mathml="K→FU”>K→FU,则<span data-mathml="K”>K称为<span data-mathml="R”>R的候选码(candidate key)
  • 主码:
    • 什么是主码?主码来自候选码,主码只有一个,但是主码可以是一个属性或多个属性组成,如Sno可以或(Sno,Sname)括号里面的都是主属性
    • 细节:候选码中的谁都可以是主码,但主属性只有一个
    • 课本原文:若关系模式<span data-mathml="R”>R有多个候选码,则选定其中的一个为主码
  • 超码:
    • 什么是超码?是在主码间扩招出来的,如:(Sno,Sage)Sno主码加Sage形成一个超码,候选码就是最小的超码
    • 课本原文:如果<span data-mathml="U”>U部分函数依赖于<span data-mathml="K”>K,即<span data-mathml="K→PU”>K→PU,则<span data-mathml="K”>K称为超码(surpkey)。候选码是最小的超码,即<span data-mathml="K”>K的任意一个真子集都不是候选码
  • <span data-mathml="U”><span data-mathml="K”><span data-mathml="K→PU”><span data-mathml="K”><span data-mathml="K”>全码:
    • 什么是全码?所有属性组成,才能确定一条记录
    • <span data-mathml="U”><span data-mathml="K”><span data-mathml="K→PU”><span data-mathml="K”><span data-mathml="K”>  
  • <span data-mathml="U”><span data-mathml="K”><span data-mathml="K→PU”><span data-mathml="K”><span data-mathml="K”>外码(外部码):
    • <span data-mathml="U”><span data-mathml="K”><span data-mathml="K→PU”><span data-mathml="K”><span data-mathml="K”>什么是外码?不是本表中的属性,参考于其它表中的属性,来确定信息
    • <span data-mathml="U”><span data-mathml="K”><span data-mathml="K→PU”><span data-mathml="K”><span data-mathml="K”>例子:SC(Sno,Cno,Grade)中,Sno不码,Sno是Student(Sno,Sdept,Sage)的码,则Sno是SC的外码
    • <span data-mathml="U”><span data-mathml="K”><span data-mathml="K→PU”><span data-mathml="K”><span data-mathml="K”>课本原文:关系模式<span data-mathml="R”>R中属性或属性组<span data-mathml="X”>X并非<span data-mathml="R”>R的码,但<span data-mathml="X”>X是另一个关系模式的码,则称<span data-mathml="X”>X是<span data-mathml="R”>R的外部码(foreign key),也称外码,主码与外码一起提供了表示关系(表)间的联系的手段      
  • 主属性和非主属性:
    • 主属性和非主属性是针对,候选码和主码来说的
    • 主属性:
      • 什么是主属性?包含在任何一个候选码中的属性,称为主属性
    • 非主属性:
      • 什么是非主属性?不包含在任何候选码中的属性
    •                                       

<span data-mathml="X→传递Z”>6.2.3 范式:

  • 什么是范式?满足一种级别的关系模式的集合
    • 理解:关系数据库中的表,必须满足不同的要求,满足的程度不同就是不同的范式 
  • 各种范式之间的存在联系:
    • 5NF<span data-mathml="⊂”>⊂4NF<span data-mathml="⊂”>⊂BCNF<span data-mathml="⊂”>⊂3NF<span data-mathml="⊂”>⊂2NF<span data-mathml="⊂”>⊂1NF 
      • 理解:2NF保护1NF,3NF包含2NF(2NF是包含1NF的),以此类推  
    •   
  • 规范化:是指一个低一级范式的关系模式,提供模式分解转换为若干个高一级范式的关系模式集合的过程
    • 模式分解:可以理解为把一个关系表分解为多个关系表            
  • 第一范式-1NF:只要基本表中不出现,像合并单元格的就是第一范式,第一范式是基本前题
  • 第二范式-2NF:非主属性(非候选码),要完全函数依赖于任何一个候选码
    • 理解:一个表中函数依赖关系必须是完全函数依赖,不能是其他依赖
  • 例子:S-L-C(Sno, Sdept, Sloc, Cno, Grade),Sloc 为学生的住处,并且每个系的学生住在同一个地方。S-L-C的码为 (Sno,Cno),则函数依赖有:
  • (Sno, Cno)<span data-mathml="→F”>Grade –> 完全函数依赖

    Sno<span data-mathml="→”>→Sdept,

  • <span data-mathml="→”>(Sno, Cno)Sdept –> 部分函数依赖,不符合第二范式

    Sno<span data-mathml="→”>→Sloc,

  • <span data-mathml="→”>(Sno, Cno)<span data-mathml="→”><span data-mathml="→P”>Sloc-> <span data-mathml="→”><span data-mathml="→P”>部分函数依赖,不符合第二范式

    Sdept<span data-mathml="→”>→Sloc(每个系的学生只住一个地方)

  • 函数依赖关系如下:
    • 实线是完全函数依赖
    • 虚线是部分函数依赖  
  • 出现例子上不能形成第二范式的原因是,sdept、Sloc它是部分函数依赖
  • 解决办法:
    • 用投影分解把关系模式S-L-C分解(前面说到的模式分解)成两关系,消除部分函数依赖
  • SC(Sno,Cno,Grade) 和 S-L(Sno,Sdept,Sloc) 
    • 虽然分成了两个表,都是是有通过Sno进行表的联系
  • 一个关系模式不属于第二范式,产生的问题:
    • 插入异常、删除异常、修改复杂    
  • 第三范式-3NF:不能有传递依赖存,第三范式是包含第二范式,第三范式是在第二范式上改进(上述以说)
  • 例子:S-L(Sno,Sdept,Sloc)该关系是上述案例模式分解出来的,它存在函数依赖,Sno -> Sdept -> Sloc,把该问题解决就可以升级为第三范式
  • 解决办法:S-D(Sno,Sdept)和D-L(Sdept,Sloc),该两个关系中就不存在函数依赖  
  • BCNF范式:BCNF范式是第三范式改进版
    • 满足如下条件的就是BC范式:
      • 1.所有非主属性对每一个候选码都是完全函数依赖
        • 理解:不是码的值,必须对候选码完全函数依赖   
      • 2.所有主属性对每一个不包含它的候选码也是完全函数依赖
        • 理解:码可以推出码,如Sno -> Sname(Sname不能重复)  
      • 3.没有任何属性完全函数依赖于非码的任何一组属性
        • 理解:就是非码,不能推出依赖关系
  • 例子:C(Cno,Cname,Pcno),它只有一个码 Cno,没有任何属性对 Cno 部分依赖或传递依赖, 所以 C<span data-mathml="∈”>∈3NF。同时 C 中 Cno 是唯一的决定因素,所以 C<span data-mathml="∈”>∈BCNF
    • 理解:Cno -> Cname ;Cno -> Pcno,依赖关系都是候选码符合条件第2点,没有依赖关系符合第3点,第2点也符合
  • 例子:S(Sno,Sname,Sdept,Sage),假定 Sname 也具有唯一性,那么 S 就有两个码,这两个码都由单个属性组成,彼此不相交。其他属性不存在对码的传递依赖与部分依赖,所以 S<span data-mathml="∈”>∈3NF。同时 S 中除 Sno,Sname 外没有其他决定因素,所以 S 也属于 BCNF
    • 理解:Sno Sname; (Sno,Sname)-> Sdept; (Sno,Sname) -> Sage ;Sno -> Sdept ;Sno-> Sage ;Sname -> Sage 符合条件的3点  
  • 例子:关系模式<span data-mathml="SJP(S,J,P)”>SJP(S,J,P)中,<span data-mathml="S”>S是学生,<span data-mathml="J”>J表示课程,<span data-mathml="P”>P表示名次。每一个学生选修每门课程的成绩有一定的名次,每门课程中每一名次只有一个学生(即没有并列名次)
    • 理解:(<span data-mathml="(S,J)→P”>S,J)→P;(J,P) -> S ,<span data-mathml="(S,J)”>(S,J)与<span data-mathml="(J,P)”>(J,P)都可以作为候选码     
  • 例子:关系模式<span data-mathml="STJ(S,T,J)”>STJ(S,T,J)中,<span data-mathml="S”>S表示学生,<span data-mathml="T”>T表示教师,<span data-mathml="J”>J表示课程。每一教师只教一门课,每门课有若干教师,某一学生选定某门课,就对应一个固定的教师。由语义可得到函数依赖<span data-mathml="(S,J)→T”>(S,J)→T ,<span data-mathml="(S,T)→J”>(S,T)→J,<span data-mathml="T→J”>T→J。
    • 理解:因为没有任何非主属性对码传递依赖或部分依赖,<span data-mathml="STJ∈”>STJ∈3NF,因为<span data-mathml="T”>T是决定因素,而<span data-mathml="T”>T不包含码, 所以<span data-mathml="STJ∉”>STJ∉BCNF

6.3 数据依赖的公理系统:

  • 闭包:
    • 什么是闭包?就是通过候选码去推导出它的函数依赖(个人理解)
    • 课本原文:在关系模式<span data-eeimg="1" data-tex="R“><span data-mathml="R<U,F>”>R中为<span data-mathml="F”>F所逻辑蕴涵的函数依赖的全体叫作<span data-mathml="F”>F的闭包(closure),记为<span data-mathml="F+”>F+
    • 闭包记作:
    • 例子1:

    • 例子2:

    • 例子3:

    • 例子4:

    • 例子5:

  • 求候选码:
    • 什么是求候选码?就是通过函数一拉的两边的出现属性,通过属性的闭包来确定候选码
    • 怎么求?:如果函数一拉的左边出现,拼接和N合并去求闭包,看是否可以求出完整的闭包(就是整个R),能求出完整的闭包就是候选码
      • 如果有LR两边都出现的,就需要拿L去拼接去求闭包,拼接求出来完整闭包,的LR就不能在用来下一次的拼接
      • R不要理      
    • L表示属性只在函数依赖的左边出现
    • R表示属性只在函数依赖的右边出现
    • LR表示属性只在函数依赖的左右边出现
    • N表示函数依赖的两边都不出现    
    • 例子1:

    •     
    • 例子2:
    •                                         

<span data-mathml="Y⊆X”><span data-mathml="X→Y”>