什么是第一范式?
字段不可再分。比如要存储用户的视力,有左眼视力和右眼视力,那么我们不应该使用 eyes 来存储,而是应该使用 left_eye 和 right_eye。
第一范式有什么缺点?
比如我们下面这张表,是符合第一范式的每个字段都不可再分要求的。
| 学号 | 姓名 | 系名 | 系主任 | 课名 | 分数 |
|---|---|---|---|---|---|
| 1 | 小明 | 经济系 | 王强 | 高等数学 | 95 |
| 1 | 小明 | 经济系 | 王强 | 大学英语 | 87 |
| 2 | 小红 | 经济系 | 王强 | 高等数学 | 72 |
| 2 | 小红 | 经济系 | 王强 | 大学英语 | 98 |
- 为了存储小明一门课的学习成绩,我们就需要存储一遍系名和系主任,二门课就要存储两遍,所以这里存在数据冗余问题。
- 如果此时我们要新建一个系,那么是比较奇怪的,因为我们只有系名、系主任字段,并没有其他字段。
- 如果我们要删除某个学生,那么就会导致系消失。
- 如果某个学生现在要转系,那么就需要把他的每条数据的系名、系主任都修改。
什么是第二范式?
- 在第一范式的基础上,要有键(可由多字段组成)。
- 所有字段分别完全依赖于键。
- 如果键是多个字段组合,则不允许部分依赖于该键。
键相当于一个 key,比如学号就是一个键,因为通过学号,我们就可以获取到姓名。通过学号加课名这个多字段键,我们就可以确定分数。
所以在上面的例子中:姓名依赖于学号。
在这个表中,我们的键是学号,课名,姓名只依赖学号,并不依赖课名,所以姓名部分依赖这个键,所以这个表不符合第二范式。
我们可以尝试改进一下,把上面的表分为选课表和学生表。选课表的键是学号,课名。学生表的键是学号。
| 学号 | 课名 | 分数 |
|---|---|---|
| 1 | 高等数学 | 95 |
| 1 | 大学英语 | 87 |
| 2 | 高等数学 | 72 |
| 2 | 大学英语 | 98 |
| 学号 | 姓名 | 系名 | 系主任 |
|---|---|---|---|
| 1 | 小明 | 经济系 | 王强 |
| 2 | 小红 | 经济系 | 王强 |
一个表中可以有多个键,比如学生表中如果有身份证号码的话,那么也可以用来确定一个学生,所以我们平时也会有主键的说法,表示最重要的那个键。
什么是第三范式?
- 表中不能有间接依赖。
在学生表中学号可以确定系名,再用系名确定系主任,所以系主任间接依赖学号。明显的问题是:如果我们删除学生,则会影响某个系的存在,或者当某个系的系主任发生变化时,我们要大量修改学生表的数据。所以我们可以做下面这样的拆分:
| 学号 | 姓名 | 系名 |
|---|---|---|
| 1 | 小明 | 经济系 |
| 2 | 小红 | 经济系 |
| 系名 | 系主任 |
|---|---|
| 经济系 | 王强 |
| 经济系 | 王强 |
一对一的关系如何建表?
在任意一个表中存储另外一个表的主键。
一对多的关系如何建表?
- 如果数据库支持数组,那么可以在 “一” 的表中增加一列,数据为 “多” 的这张表的主键数组。这种方法可能不利于扩展与搜索。
- 推荐:建立 1 个关系表,包含 2 个表的主键即可。
多对多的关系如何建表?
与「一对多的关系如何建表」类似,推荐使用关系表来维护关联关系。