# 这张表是第几范式：从函数依赖判断，到该不该拆、怎么拆

用一个学生选课的关系模式，完整走一遍找候选键、判 1NF 到 3NF、识别冗余与更新异常、拆成四个模式并自查的过程

> 综合知识 · 题型分析 · 备考策略 · 约 6 分钟 · 10 月 21 日

## 本篇要点

1. 函数依赖 $X \to Y$ 表示同一个 $X$ 只对应一个 $Y$，方向不能反用；范式判断只用题面给出的依赖集，不靠常识补充。
2. 候选键用闭包求：从一组属性出发不断套用依赖，直到属性集不再增长，再确认删掉任一属性就推不出全部；本题候选键是（学号, 课程号）。
3. 先标主属性与非主属性，2NF、3NF 的判断都只针对非主属性。
4. 2NF 只被复合键违反：非主属性只依赖键的一部分即部分函数依赖；本题 学号 → 姓名、课程号 → 课程名 使最高范式停在 1NF。
5. 3NF 只被传递依赖违反，需同时满足 $X \to Y$、$Y \to Z$ 且 $Y$ 不决定 $X$；本题 学号 → 系名 → 系主任 使含这条链的模式停在 2NF。
6. 范式对应的是冗余、更新异常、插入与删除异常，拆分的依据是让每条依赖的左边成为一个键。
7. 本题最终拆成（学号,姓名,系名）、（系名,系主任）、（课程号,课程名）、（学号,课程号,成绩）四个 3NF 模式。
8. 结果可以自查：重算每个模式的候选键、对非主属性核对“只依赖键、依赖整个键、只依赖这个键”、检查拆出的两个模式公共属性能否决定一侧的其他属性、原依赖是否都落到某个模式里。
9. 范式级别取决于函数依赖集而非表名或字段长相；去掉 系名 → 系主任 后，同一字段列表直接拆成三个模式就到 3NF。
10. 2NF、3NF 只约束非主属性，全部属性都落在候选键里时可能满足 3NF 却不满足 BCNF。

---

综合知识卷里数据库那几道题，最常见的问法是：给一个关系模式和一组函数依赖，问候选键是什么、最高属于第几范式、存在什么问题、怎么分解。这类题答案唯一，可以按固定顺序走，走完还能自己验算。下面这道题，建议先盖住后半篇自己判一遍。

## 先摆题目

关系模式 R（学号, 姓名, 系名, 系主任, 课程号, 课程名, 成绩），函数依赖集是：

- 学号 → 姓名，学号 → 系名
- 系名 → 系主任
- 课程号 → 课程名
- （学号, 课程号） → 成绩

这张表记的是“谁选了哪门课、得了多少分”。

## 函数依赖：知道左边，右边就定了

$X \to Y$ 的意思是：同一个 $X$ 只对应一个 $Y$ [1]。学号 → 系名，一个学号只属于一个系；系名 → 系主任，一个系只有一个主任。

注意方向：箭头反过来不一定成立。课程号 → 课程名 成立，课程名 → 课程号 不成立，不同课程重名是可能的。判断时随手反用箭头，后面的键和分解全错。另外，依赖集是题面给的业务规则，不要凭“现实里应该还有”去补。

## 第一步：用闭包找候选键

候选键是能推出全部属性、而且再删掉任一属性就推不出全部的最小属性组 [1]。手算方法叫闭包：从一组属性出发，凡是左边已被包含的依赖就可以拿来用，把右边不断加进来，直到不再增长。

- 从 **学号** 出发：学号 → 姓名、学号 → 系名，再用 系名 → 系主任，得到 {学号, 姓名, 系名, 系主任}。缺课程号、课程名、成绩，不够。
- 从 **课程号** 出发：只有 {课程号, 课程名}，不够。
- 从 **（学号, 课程号）** 出发：上面两组结果都能拿到，再加（学号, 课程号） → 成绩，七个属性全齐。

再看最小性：去掉学号只剩课程号，不够；去掉课程号只剩学号，也不够。候选键唯一，是 **{学号, 课程号}**。

顺手标出主属性：出现在候选键里的属性（学号、课程号）是主属性，其余五个（姓名、系名、系主任、课程名、成绩）是非主属性。后面两步的判断只针对非主属性。

## 第二步：1NF 只看字段还能不能再分

每个属性都是原子值，1NF 通过。软考很少在这一层设障，除非题面出现“地址”这类可拆字段，或者把多门课塞进一格。

## 第三步：2NF 看有没有只依赖半个键

2NF 要求：不存在非主属性对候选键真子集的依赖，这种依赖叫部分函数依赖。两个限定词都要看清：只有复合键才可能违反（单属性键没有真子集可用）；而且被依赖出来的是非主属性。

本题的键是（学号, 课程号）。学号只是键的一半，而 学号 → 姓名、学号 → 系名 都成立，姓名、系名又是非主属性，这就是部分依赖。课程号 → 课程名 同理。所以最高范式是 **1NF**，连 2NF 都没到。

## 第四步：3NF 看有没有绕道

3NF 在 2NF 之上要求：不存在非主属性对候选键的传递函数依赖 [2]。判断传递依赖要三个条件同时成立：$X \to Y$、$Y \to Z$，而且 $Y$ 不能反过来决定 $X$（否则两边互相决定，不算绕道），三个属性集互不相交 [2]。

本题：学号 → 系名 → 系主任。系名不决定学号（一个系有多个学生），所以 学号 → 系主任 是传递依赖。这条链即使把表拆到 2NF 也还在，卡住的就是 3NF。

## 问题到底出在哪

- **冗余**：一个系有几百个学生，系主任的名字就在几百行里各存一份，按选课记录算重复得更多。
- **更新异常**：换系主任要改一大批行，漏改一行，同一个系就冒出两个主任。
- **插入、删除异常**：新成立一个系、还没有人选课，系主任这条事实没地方写；把一个系的选课记录全删掉，系主任的信息也跟着消失。

范式的目标就是让一个事实只存在一个地方。只要还有这种跟着别的数据重复的非主属性，就值得拆。

## 怎么拆

先拆到 2NF：把依赖键一部分的属性和依赖整个键的属性分开。

- R1（学号, 姓名, 系名, 系主任），键是学号
- R2（课程号, 课程名），键是课程号
- R3（学号, 课程号, 成绩），键是（学号, 课程号）

再拆到 3NF：R1 里 学号 → 系名 → 系主任 这条链还在，把“系”这一层独立出去：

- R11（学号, 姓名, 系名），键是学号
- R12（系名, 系主任），键是系名

R2、R3 保持不动。四个模式里，每个非主属性都只直接依赖自己那张表的键，全部到 3NF。

## 怎么知道自己判对了

**一、回到每个新模式重算候选键。** R12 只剩系名和系主任，键就是系名。算出来和你设想的不一样，说明拆错了。

**二、对每个非主属性问三句。** 只依赖这个键？依赖整个键？除了这个键不依赖别的？这就是 “the key, the whole key, and nothing but the key” [2]。

**三、检查有没有丢信息。** 每一步拆出来的两个模式，公共属性能决定其中一侧的其他属性：R11 和 R12 公共属性是系名，系名 → 系主任，拼得回原样；R2 和 R3 公共属性是课程号，课程号 → 课程名，同样成立。再看原依赖有没有丢，本题四条都完整落在某个模式里。

## 条件一变，答案就变

把 系名 → 系主任 从题面拿掉：R1 变成（学号, 姓名, 系名），键是学号，姓名和系名都直接依赖它，没有传递依赖，拆成三个模式就到 3NF，R12 不存在。可见决定范式的是函数依赖集，不是表名或字段长相，“学生选课表就是 1NF”这种记法不成立。

如果键只有单属性（比如把成绩拿掉，R（学号, 姓名, 系名, 系主任）），就不会有 2NF 问题，只可能卡在 3NF。所以必须按 1NF → 2NF → 3NF 的顺序判，不能跳步。

## 一处边界

2NF、3NF 的规则全都冲着非主属性去。如果所有属性都出现在某个候选键里（学生—教师—课程这类多候选键的结构就是这样），表里没有非主属性，按定义可同时满足 2NF 和 3NF，却可能因为某个依赖的左边推不出全部属性而不满足 BCNF [3]。所以见到 BCNF 选项时，判法是另一句话：每条非平凡依赖的左边，是不是能推出全部属性。

## 术语表

- 函数依赖：在这张表里，知道 X 的值就能唯一确定 Y 的值，记作 $X \to Y$，方向反过来不一定成立。
- 闭包：从一组属性出发反复套用依赖、把右边加进来，直到不再增长，用来求候选键。
- 候选键：能推出全部属性、删掉任一属性就推不出全部的最小属性组。
- 主属性：出现在任何一个候选键里的属性；不在任何一个候选键里的叫非主属性。
- 部分函数依赖：非主属性只依赖复合键的一部分，是 2NF 要排除的情况。
- 传递函数依赖：键经过另一个非主属性间接决定某属性，且中间那个属性不能反过来决定键，是 3NF 要排除的情况。

## 来源

1. [Functional dependency — 函数依赖与候选键的定义](https://en.wikipedia.org/wiki/Functional_dependency)
2. [Third normal form — 3NF 定义、传递依赖的三个条件与 Kent 的判据表述](https://en.wikipedia.org/wiki/Third_normal_form)
3. [Boyce–Codd normal form — BCNF 的定义，以及无主属性时自动满足 3NF 的说明](https://en.wikipedia.org/wiki/Boyce%E2%80%93Codd_normal_form)

---

原文：https://pangzhengboyin.com/articles/normal-forms-functional-dependency-example-2c8f02d1

> **庞征博引** · 想学的，慢慢都会
>
> 庞征博引是把想学的东西写成连载的 AI 学习工具。说出想学什么，它会先了解你的基础，再把主题写成一篇篇 5–10 分钟能读完的文章；边读边问，接下来学什么跟着你走。这篇就是这样写出来的。
>
> 开始你自己的连载 → https://pangzhengboyin.com
