三大范式再认识

前言

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

  • 当实体 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. 数据库的三大范式(原理 + 例子详解)|☆☆☆

你可能感兴趣的:(mysql范式)