前言

说起三大范式,我脑海里第一反应就是这几句话:

  • 当实体 A 与实体 B 之间的关系是一对一时,会把实体 A 的主键作为 实体 B 的外键。当然关系是一对一时,反过来也可以,即把 实体B 的主键当做实体 A 的外键;
  • 当实体 A 与实体 B 之间的关系是一对多时,会把 A 的主键当做实体 B 的外键;
  • 当实体 A 与实体 B 之间的关系是多对多时,通常会考虑建一张新表来保存这两个实体之间的关系。

但是有时候实体与实体之间的关系并不是非常容易的看出来,所以靠这些理解并不足以设计出符合规范的表结构。在读了相应的资料后,发现自己对三大范式的理解是非常浅薄的、肤浅的,所以就写了这篇博客来记录自己对三大范式重新认识的过程。

什么是范式(NF)?

在理解三大范式之前,需要明白什么是范式(NF)?

按照教材中的定义,范式是:

符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度。

可以理解为:一张数据表的表结构所符合的某种设计标准的级别

三大范式定义

以下是三大范式的定义:

  • 第一范式:符合 1NF 的关系中的每个属性都不可再分。
  • 第二范式:2NF1NF 的基础之上,消除了非主属性对于码的部分函数依赖。
  • 第三范式:3NF2NF 的基础之上,消除了非主属性对于码的传递函数依赖。

说实话,我一开始看到第二范式和第三范式的定义时,感到非常迷惑:

  • 什么是非主属性?
  • 什么是码?
  • 范式的定义为什么和函数有关?

但是在理解了这些概念之后,才意识到意识到这几条定义是如此的精确。

在理解“非主属性”和“码”之前,需要先彻底搞明白什么是“函数依赖”,因为“非主属性”和“码”的概念是建立在“函数依赖”的概念之上的。

什么是函数依赖?

若在一张表中,在属性(或属性组)X的值确定的情况下,必定能确定属性Y的值,那么就可以说Y函数依赖于X,写作 X → Y。

光看概念可能不太好理解什么是函数依赖,还是需要通过一个例子来理解。

学生表如下:

学号姓名性别年龄
1420233906罗辑21
1420233907云天明22
1420233908章北海23
1420233909程心20

这张学生表有四个属性:学号、姓名、性别、年龄。我们知道一个学号对应一个学生,假如你的班主任问你 1420233906 是谁,你就可以告诉他 1420233906 是罗辑,除此之外,你还能告诉你的班主任,罗辑是男的,21 岁。

换句话说:

  • 在学号确定的情况下,就必定能确定姓名的值,即姓名函数依赖于学号,写作姓名 → 学号;
  • 在学号确定的情况下,就必定能确定性别的值,即性别函数依赖于学号,写作性别 → 学号;
  • 在学号确定的情况下,就必定能确定年龄的值,即年龄函数依赖于学号,写作年龄 → 学号;

还能在学生表中找到其他的函数依赖关系吗?答案是否定的。

如果学生表中,只有这四条记录,好像是可以通过姓名来确定学号、性别、年龄的值。但是在大多数班中肯定存在同名同姓的学生,例如张伟:

学号姓名性别年龄
1420233906罗辑21
1420233907云天明22
1420233908章北海23
1420233909程心20
1420233909张伟21
1420233910张伟22

虽然同叫张伟,但却是两个不同的学生。当数学老师叫张伟时,两个张伟可能同时站起来。即在姓名确定的情况下,无法确定学号的值,无法确定性别的值也无法确定年龄的值。同理:

  • 在性别确认的情况下,无法确定其他任意一个属性的值;
  • 在年龄确认的情况下,无法确定其他任意一个属性的值;

再来看一个更难的例子:

学号姓名系名系主任课名分数
1420233906罗辑机电工程系艾AA高等数学99
1420233907罗辑机电工程系艾AA大学英语98
1420233908罗辑机电工程系艾AA大学物理97
1420233909程心经济系维德高等数学88
1420233909程心经济系维德毛概88
1420233910程心经济系维德大学英语88

在这张表中存在哪些函数依赖关系呢?

  • 学号 → 姓名
  • 学号 → 系名(一个学生只属于一个系)
  • 系名 → 系主任(一个系只有一个系主任)
  • 学号 → 系主任(一个学生只属于一个系、一个系只有一个系主任,即在学号确定的情况下,必定可以确认该学生所属系的系主任)
  • (学号,课名) → 分数

但是以下函数依赖关系则不成立:

  • 学号 → 课名
  • 学号 → 分数
  • 课名 → 分数
  • ...

从“函数依赖”这个概念展开,还会有三个概念:

1)完全函数依赖

在一张表中,若 X → Y,且对于 X 的任何一个真子集(假如属性组 X 包含超过一个属性的话),X ' → Y 不成立,那么我们称 Y 对于 X 完全函数依赖,记作 X F→ Y

例如:(学号,课名) F→ 分数,即分数完全函数依赖于(学号,课名)属性组。

  • 属性 Y 要完全函数依赖于属性(组)X 的前提是:属性 Y 要函数依赖于属性(组)X,分数函数依赖于(学号,课名),第一条满足;
  • (学号,课名)是一个属性组,超过一个属性,它的真子集有{学号}、{课名},无法只通过学号来确定分数,也无法只通过课名来确定分数,故满足对于(学号、课名)的任何一个真子集,X' → Y 不成立。

所以分数完全函数依赖于(学号,课名)属性组成立。

2)部分函数依赖

假如 Y 函数依赖于 X,但同时 Y 并不完全函数依赖于 X,那么我们就称 Y 部分函数依赖于 X,记作 X P→ Y

例如:(学号,课名) P→ 姓名,即姓名部分函数依赖于(学号,课名)组。

  • 首先姓名函数依赖于(学号,课名)属性组成立;
  • (学号,课名)的真子集为{学号}、{课名},在这些真子集中,可以通过学号来确定姓名,即姓名函数依赖于学号,故姓名不完全函数依赖于(学号,课名)属性组,即姓名部分函数依赖于(学号,课名)。

3)传递函数依赖

假如 Y 不包含于 X,且 X 不函数依赖于 Y,Z 函数依赖于 Y,且 Y 函数依赖于 X,那么我们就称 Z 传递函数依赖于 X ,记作 X T→ Z。

什么是码?

设 K 为某表中的一个属性或属性组,若除 K 之外的所有属性都完全函数依赖于 K(这个“完全”不要漏了),那么我们称 K 为候选码,简称为码。

什么是非主属性

主属性之外的属性就是非主属性。

参考

  1. 第一范式、第二范式、第三范式详解|☆☆☆☆☆
  2. 三张图搞透第一范式(1NF)、第二范式(2NF)和第三范式(3NF)的区别|☆☆☆☆
  3. 真子集和子集有什么区别?|☆☆
  4. 数据库的三大范式(原理 + 例子详解)|☆☆☆

Moonshadow2333
28 声望0 粉丝

征途漫漫


« 上一篇
触发器
下一篇 »
反射