关系模型胜在有数学根基;本章给出「关系」的严格定义与它的运算——关系代数。
关系(Relation) 是一张表,但更严格:它是笛卡尔积的一个子集。
学号域 = {S001, S002, ...}。R(A1, A2, ..., An),如 Student(学号, 姓名, 系)。三条性质:列同质(每列来自同一域)、行无序、列无序(靠名字不靠位置)、不能有重复元组(集合语义,与 SQL 表的多重集语义不同)。
Student(学号, 姓名, 系)
┌──────┬──────┬────┐
│ S001 │ 张三 │ CS │ ← 一个元组
│ S002 │ 李四 │ EE │
└──────┴──────┴────┘
↑ 属性(域 = 所有合法学号)
Student(学号 PK, 姓名, 系)
SC(学号 FK, 课程号 FK, 成绩) —— SC 的两个外码共同引用 Student 和 Course
{学号, 姓名} 也能唯一标识人,但去掉「姓名」仍唯一,故不是候选码——候选码不能有冗余属性。
| 约束 | 规则 | 违反示例 |
|---|---|---|
| 实体完整性 | 主码不能取空值 | 学生没有学号 |
| 参照完整性 | 外码要么为空,要么等于被参照表某主码值 | 选了不存在的课程号 |
| 用户定义完整性 | 语义约束(取值范围等) | 成绩 < 0 或 > 100 |
实体完整性保证「每行能被找到」;参照完整性保证「引用不悬空」。两者由 DBMS 自动强制,即第 3 章的 PRIMARY KEY/FOREIGN KEY。
关系代数:输入/输出仍是关系的集合运算。常用运算:
| 运算 | 记号 | 作用 |
|---|---|---|
| 选择 σ | 挑行(按条件过滤元组) | |
| 投影 π | 挑列(去重) | |
| 连接 ⋈ | 按条件拼两个关系 | |
| 除 ÷ | 找「满足 S 全部」的元组 | |
| 并 ∪ / 交 ∩ / 差 − | 集合运算 | 要求两关系结构相容 |
σ_{系='CS'}(Student) → 只保留 CS 的学生行
π_{姓名}(Student) → 只剩「姓名」一列,且去重
Student ⋈_{学号=学号} SC → 学生和选课按学号拼成宽表
连接最贵也最常用,等价于「先笛卡尔积,再选择」;第 4 章内/外连接、第 9 章连接优化源头在此。
除(÷):SC ÷ Course 求「选了所有课程的学生」,专门回答「对全部的…」类查询。
对比:关系代数 vs 关系演算——关系代数过程式,明确写「先选谁、再连谁」,对应 SQL 执行顺序;关系演算(元组/域演算)声明式,只描述「满足条件的元组」,是 SQL
WHERE的灵感。二者表达能力等价,SQL = 代数内核 + 演算外观。对比:关系 vs 非关系——关系模型靠表和值匹配表达联系,强在一致性与复杂查询;非关系(文档、KV、图,见第 10 章)放弃部分一致性换扩展性。