范式是从英文Normal Form翻译过来的,这里主要说前面3个范式。这3个范式步步为营,后面的范式必须以前面范式为基础,如果没有实现第一范式,那么是不可能实现第二范式的,更别说第三范式了。这3个范式的提出都是为了避免数据冗余和插、改、删的操作异常。
1、第一范式(1NF):强调列的原子性,要求每一列都不能再细分。举例,有张学生信息表:学号、姓名、班级。这里列“班级”就不是原子的,因为可以拆分为“年级”和“班级”。如果不拆分就会导致数据冗余,如:
学号 姓名 班级
1 张三 高三1班
2 李四 高三2班
3 王五 高一1班
从上面可以看到“班级”里的年级是重复的,这个倒还好,问题是如果现在我们需要修改年级,比如“高三”改成“毕业班”,那就麻烦了,只能整张表去“班级”里一个一个改。
2、第二范式(2NF):在1NF的基础上,两个要求,一是必须有主键,二是非主键必须完全依赖主键。第一个要求好理解,第二个要求就不是那么容易理解了。其实很简单,因为要求其他列不能只依赖部分主键,就说明了必须要有两个或两个以上才能会有部分主键的说法。因此只有联合主键才会出现满足不了2NF的情况,说白了就是两个主键拆分成两张表。再举个例子:
学号 姓名 年级 班级 课程 最高分 成绩
1 张三 高三 1班 语文 100 80
2 李四 高三 2班 语文 100 78
3 王五 高一 1班 英语 150 123
1 张三 高三 1班 数学 120 49
2 李四 高三 2班 数学 120 113
我们已经满足了1NF,但现在表里多了课程和最高分,我们有两个主键了:学号和课程。姓名、年级、班级和成绩都依赖学号;最高分依赖课程而不是学号。这种情况就叫做依赖主键的一部分。从上面看,很明显数据冗余了,而且如果要修改“语文”的“最高分”为150,那么还是只能整表一个一个修改;如果学校取消“英语”课程了,删掉“英语”也就删掉“王五”了,可怜的王五就没成绩记录了;如果新增一个“物理”课程,最高分“180”,那么对不起,没法插进来,因为目前还没人报考,没有“学号”主键和依赖它的列。
3、第三范式(3NF):在2NF的基础上,非主键必须直接依赖主键。2NF是要完全依赖,这里是要直接依赖,不能有依赖传递的情况。比如列C依赖列B,列B依赖列A,而A才是主键,那么列C就是传递依赖于主键A。这种情况也必须拆分成两张表。举例:
学号 姓名 年级 班级 班主任 班主任手机号
1 张三 高三 1班 张老三 13811111111
2 李四 高三 2班 张老三 13811111111
3 王五 高一 1班 王老五 13922222222
目前只有一个主键“学号”,姓名、年级、班级、班主任、班主任手机号都依赖于主键,所以符合2NF。但是“班主任手机号”存在传递依赖,因为它依赖于“班主任”,“班主任”依赖于“学号”。数据依然冗余,班主任换手机号的话还是得多处修改,新增个班主任同样存在没地方放的情况,删个手机号也有可能把班主任给删没了。
这里2NF和3NF有点不好区分,关键还是看是否联合主键。单主键不会出现主键部分依赖的问题。