# 关系数据库模型

> CIE A-Level 计算机科学 · 9618
> 来源: https://www.owlsprep.com/zh/study/cie-9618-u8-relational-database-model/

本模块介绍E.F. Codd提出的关系数据库模型，它是现代结构化数据存储的全球标准。你将学习核心术语、关键属性、键的类型，以及数据之间联系的结构。

**先修:** [数据库简介](https://www.owlsprep.com/zh/study/cie-9618-u8-introduction-to-databases/)

## 学习目标

- 理解关系数据库模型的核心原理
- 区分不同类型的关系键
- 命名并解释关系的核心属性
- 识别并构建关系之间联系的模型

## 关系模型的核心组件

**关系数据库模型** — 一种结构化数据模型，将数据组织为一个或多个独立的关系，并规定了数据在关系之间链接的正式规则，旨在消除文件系统的数据冗余和不一致问题。

*例:* 大学数据库将学生、课程和注册数据拆分为三个相互链接的独立关系。

关系模型对核心组件使用统一的术语，这些术语是CIE考试要求你必须记住的：

- **关系**：完整的二维数据结构（在实现中通常称为表）
- **元组**：关系中单个完整的记录（通常称为行）
- **属性**：所有元组共有的单个特性（通常称为列）
- **域**：属性允许的有效值集合

**例题:** 对于图书馆图书借阅系统，请将下列内容分类为关系、元组或属性：(1) `checkout_date`，(2) `Member`，(3) (1001, "Priya Mehta", "2024-01-15")

1. 回忆每种组件类型的定义：
2. 1. `checkout_date`描述所有借阅记录的单个特性，因此它是一个**属性**
3. 2. `Member`是所有图书馆会员记录的完整集合，因此它是一个**关系**
4. 3. (1001, "Priya Mehta", "2024-01-15")是单条完整的会员记录，因此它是一个**元组**

> **考试提示:** CIE阅卷员只有在你使用正式术语时才会给满分：在要求正式定义的题目中，使用'元组'而不是'行'，使用'属性'而不是'列'。

## 键的类型

键是唯一标识元组、并在不同关系之间创建链接的核心机制。你需要区分几种不同的键类型：

**候选键** — 可以唯一标识关系中每个元组的最小属性集合（可以包含一个或多个属性）。一个关系可以有多个候选键。

*例:* 在`Patient`关系中，`patient_id`和`nhs_number`都是独立的候选键。

- **主键**：由设计者选中用来唯一标识元组的单个候选键。主键必须始终非空且唯一。
- **外键**：一个关系中匹配另一个关系主键的属性，用来在两个关系之间创建链接。

**例题:** 给定模式`Product(product_id, product_name, supplier_id, unit_price)`，其中`supplier_id`引用`Supplier(supplier_id)`，请识别`Product`关系中的主键和外键。

1. 1. 主键唯一标识每个产品。`product_id`是每个产品的唯一标识符，因此它是**主键**。
2. 2. 外键链接到另一个关系的主键。`supplier_id`引用`Supplier`关系的`supplier_id`主键，因此它是**外键**。

## 关系的核心属性

关系模型中所有有效的关系都遵循四个核心属性，考试中可能会要求你列出或解释这些属性：

- 元组无序：行的顺序不会改变关系本身
- 属性无序：列的顺序不会改变关系本身
- 属性值是原子的：每个属性仅存储其域中的一个值
- 无重复元组：所有元组都是唯一的（由候选键强制执行）

**例题:** 一名学生在`Student`关系的单个`emergency_contact`属性中存储了2个紧急联系人电话号码。这违反了哪个核心属性？解释你的答案。

1. 回忆原子性要求：每个属性只能存储其域中的一个值。
2. 在一个属性中存储两个独立的电话号码会产生多值条目，这违反了**原子性**。
3. 要解决这个问题，需要创建一个独立的`StudentEmergencyContact`关系，每个联系电话号码对应一个元组。

## 关系之间的联系

关系模型支持三种常见的关系间联系类型，根据主键和外键的结构定义：

- **一对一**：关系A中的一个元组仅链接到关系B中的一个元组（大多数用例中很少见）
- **一对多**：关系A中的一个元组链接到关系B中的多个元组（最常见的联系类型）
- **多对多**：关系A中的多个元组链接到关系B中的多个元组，需要额外的连接表

**例题:** 在大学注册系统中，每个学生选修多个模块，每个模块有多个学生，如何构建`Student`和`Module`之间联系的模型？

1. 1. 首先，识别联系类型：这是一个多对多联系。
2. 2. 多对多联系无法仅用两个关系直接建模，因为如果在一个属性中存储多个外键会违反原子性。
3. 3. 添加一个连接表（通常称为`Enrollment`），将每个关系的主键作为外键存储在其中。最终的模式如下：
4. - `Student(student_id, student_name)`
- `Module(module_code, module_name)`
- `Enrollment(student_id, module_code, semester)`
5. `Enrollment`中的每个元组代表一名学生注册一个模块，正确建模了该联系。

> **考试提示:** 要求构建多对多联系模型的题目非常常见。一定要记得添加连接表才能拿到满分。

## 常见错误

- **错误做法:** 混淆候选键和主键
  - 原因: 许多学生错误地认为一个关系只能有一个候选键，实际上只有一个候选键会被选为主键。
  - 正确做法: 一个关系可以有多个候选键；主键只是被选来做唯一标识的那个候选键。
- **错误做法:** 在单个属性中存储多个值
  - 原因: 学生经常为了节省空间，在一个单元格中存储多个值，忘记了原子性规则。
  - 正确做法: 将多值属性拆分为独立的链接关系，以符合关系模型的要求。
- **错误做法:** 忘记多对多联系需要连接表
  - 原因: 学生试图在单个属性中存储多个外键，这会破坏原子性。
  - 正确做法: 始终添加一个连接表，每个链接对应一个元组，才能正确建模多对多联系。
- **错误做法:** 认为元组或属性的顺序是关系定义的一部分
  - 原因: 电子表格等可视化工具显示有序的行/列，导致人们错误地认为顺序很重要。
  - 正确做法: 记住，根据关系的核心属性，改变行或列的顺序不会产生新的关系。
- **错误做法:** 将外键作为一对多联系中'多'端关系的主键
  - 原因: 例如，多本书可以有同一个作者，因此`author_id`无法唯一标识一本书。
  - 正确做法: '多'端需要有自己唯一的主键，外键作为额外属性存储。

## 速查表

| 术语 | 核心定义 |
| --- | --- |
| 关系 | 相关数据的完整二维表 |
| 元组 | 关系中的单条记录/行 |
| 属性 | 关系中的单个特性/列 |
| 候选键 | 元组的最小唯一标识符 |
| 主键 | 关系中被选中的候选键 |
| 外键 | 链接到另一个关系的主键 |
| 原子性 | 每个属性一个值，不允许多值 |
| 多对多 | 模型中需要连接表 |

## 下一步

关系数据库模型是数据库单元所有后续主题的基础。接下来你将学习规范化，即优化关系模式以消除数据冗余、防止更新、插入和删除异常的过程。掌握规范化之后，你将学习结构化查询语言（SQL），它是用于创建、查询和修改关系数据库的标准语言。这些主题中的所有概念都直接建立在我们这里介绍的术语、规则和结构之上，因此掌握这个子主题会让你之后所有数据库相关的学习都更容易理解。

- [结构化查询语言（SQL）](https://www.owlsprep.com/zh/study/cie-9618-u8-structured-query-language/)
- [规范化](https://www.owlsprep.com/zh/study/cie-9618-u8-normalisation/)
- [客户-服务器与分布式数据库](https://www.owlsprep.com/zh/study/cie-9618-u8-client-server-and-distributed-databases/)

---

来自 [OwlsPrep](https://www.owlsprep.com) —— A-Level / IB / AP / IGCSE 免费学习指南，依据官方考纲编写。原页面：https://www.owlsprep.com/zh/study/cie-9618-u8-relational-database-model/
