写下此文,希望能深入浅出地总结【正则化】的要点
目录
完全函数依赖(full functional dependency)
各类范式(Normal Form)
范式,可以消除表中过多数据冗余,让每个表更简洁;但也增大了跨表联系和索引数据的难度。以下为常用的各类范式(内层的范式可由外层的演变得来,对表中数据联系的要求也更高):
一、无范式(Unnormalized Form,UNF)
如关系(或者说 表)ClientRental所示,杂糅无章,看上去刚刚有个表样儿,每个单元格可以有一个到多个值(但不可为空),这就是UNF。
二、第一范式(First Normal Form,1NF)
保证每个单元格有且仅有一个值。可通过重新划分UNF得到(图中框红处为新拷贝出来的值):
三、第二范式(2NF)
在1NF的基础上,若所有非候选键(non-candidate key)的属性都完全函数依赖于候选键,则已经属于2NF;若依赖于候选键的部分函数依赖存在,则需要用将一张大表切分成多张小表(即分为多个关系)的方式去除此部分函数依赖,使得新生成的几个表都符合上述要求。
那什么是函数依赖?什么又是完全、部分函数依赖?
函数依赖(Functional Dependency)
如图,对于表中每一行,若知道B的值,就能唯一确定D的值。从B到D是1对1的关系,但这只是单向的(single direction),不是相互的,因为反过来知道D未必就能推出B(如:当D=w,B=b或d,不止一种可能)。所以B是“决定者”(determinant),也是“被依赖者”,D是“被决定者”,也是“依赖者”,D函数依赖于B,
记为 B --> D,(注意箭头指向,是“determination”的指向)
完全函数依赖(full functional dependency)
直观地说,就是对于属性集 A --> B,B完完全全只依赖于A,而不依赖于A下面的任何子集。
它的严格定义:Determinants should have the minimal number of attributes necessary to maintain the functional dependency with the attribute(s) on the right hand-side.
与之相对的,就是部分函数依赖。
部分函数依赖(partial dependency):
即使A中部分属性被剔除,A --> B仍然成立
在同一张表中,若有函数依赖:staffNo, sName -> branchNo、staffNo -> branchNo, 则 branchNo 部分依赖于(staffNo,sName),完全依赖于staffNo。
但是从1NF变到2NF的过程中,真正要剔除部分依赖的做法与上述定义还有区别:
上文所述的关系ClientRental中,共有6个函数依赖:
其中共有3个可作为主键的候选键(candidate key): (clientNo, propertyNo),(clientNo, rentStart),(propertyNo, rentStart);
在从1NF变到2NF过程中,我们真正要剔除的部分依赖应该是以下形式:
(候选键的子属性)----> (不能单独作为候选键的属性);
(打个不恰当的比方:对于一张表中的属性,候选键就像 “当家” 一般的存在,所以候选键内部的属性应该协调一致,共同决定其他属性;若候选键内部有属性脱离其他成员,去找一些别的属性只依附于自己,那就只能离开该表出去单干了)
综上所述:属性clientNo、propertyNo、rentStart均不可单独作为 ‘determinant’,皆因它们是候选键内部的成员
fd2、fd3就是这样的例子,为了符合2NF,它们的 “依赖者属性” 会被 “请” 出这个关系,与它们一同移出的还有“决定者属性”的一份copy(本尊自然是得留下的),作为新的当家主码。由此原来的关系一分为三,各自符合2NF。
(这里copy的就是clientNo、propertyNo)
四、第三范式(3NF)
在2NF的基础上,没有非候选键属性传递性依赖于候选键本身,那么传递性依赖又是什么?
传递性依赖(transitive dependency)
之前已是2NF的三个关系,它们的函数依赖:
其中关系Client、Rental已然没有传递性依赖,都进入了3NF。只有PropertyOwner中,oName经由ownerNo依赖于主键propertyNo。
解决方案与1NF到2NF相似但略有不同:“决定者” propertyNo不动,将“中间商” ownerNo的一份copy和它的“下家” oName一并抬走,ownerNo成为新关系的主键。
三个关系变成四个,各自符合3NF。