一直以来都不太明白数据库三范式的具体含义,看到知乎的这篇文章相当不错,整理到博客下多学习。
出自知乎:作者HMKenny(如有侵权请告知,立即删除)
看完各路大神的答案后顿有所悟,总结如下:
1.先要知道几个概念:
码:一个表中,可以唯一决定一个元组的属性“集合”。而主键则是可以唯一决定元组的‘某个属性’。 例如:在成绩表中(学号,课程号)合起来叫一个码,而分开看学号是主键,课程号也是主键。
非主属性:不属于码的属性。
主属性:属于码的属性。
候选键:指每个都不一样的、非空的那几个属性,有着潜在的主键意义。比如一个表中的课程号学号,系别号等等。
2.通俗的讲范式:
1)第一范式:属性不可拆分。
如:地址这个属性是可拆分成城市地区等等,不可以把地址作为一个属性
解决方案:属性拆分开来,将一个地址属性改成多个属性,按照城市地区..设置多个属性。
2)第二范式:每个表中的非主属性完全依赖于码。
特殊情况:若码只有一个属性,则必满足第二范式。
如:(学号,课程号)这个表中的码被“学生名字”部分函数依赖。即包含有学号→学生名字这种依赖关系。不符合2NF
解决方案:将部分函数依赖的部分码和依赖这些码的属性拿出来单独成表,在原表中用外键代替以前的多个属性。
个人理解:将部分单独拿出来,用一个外键在原表中代替,可以大大减少原表中的属性条数。
3)第三范式:消除非主属性之间的依赖关系,只保留非主属性与码的依赖关系。(消除传递函数依赖的另一说法,本质是一样的)
如:学号,课程号,系别,系主任。系别和系主任是非主属性,学号和课程号是主属性。但是系别和系主任这两个非主属性之间有函数依赖关系:系别→系主任。必造成传函依赖:学号→系别→系主任。不符合3NF
解决方案:将这个非主属性与其依赖的码都拿出来单独建表,并设置被依赖的属性为主键,在原表中则用外键表示。
个人理解:将相互内在关联的非主属性用一个外键在原表中表示,可以大大减少数据冗余。
4)BC范式:每个表中只有一个候选键。
如:学号,学生名字,学生QQ。我们设置学号作主键,但是学生QQ、学号这两个都是候选键,一张表中有多个候选键,不符合BC范式。
解决方案:保留一个候选键作为主键,拿出其他的候选键单独成表,将原表中的主键放入该表中。在原表中不显示这个拿出来的候选键,从而保证每个表中只有1个候选键。
个人理解:主键越少越好。一个表中的候选键越少越好。但是这个BC范式有些苛刻了,很多情况比如成绩单表(学生 课程 成绩),学生、课程为候选键,我们这样直接建表也是可以的。
设计到第三范式就行了!BC范式太苛刻了,大多数情况用不到。