进阶 #database#relational#algebra

关系模型与关系代数

关系模型(Relational Model)把数据抽象为"关系"(表),用集合论的运算(选择、投影、连接)来操作数据——SQL 就是基于关系代数设计的

🧮 ER 图画完了——然后呢?

上一节我们用 ER 图画出了选课系统的”设计图”:学生、课程、教师……看起来很清楚。

但问题是——计算机看不懂 ER 图。你不可能把一张图直接交给 MySQL 说”照着这个建表”。

我们需要一种方式把 ER 图转化为计算机能理解的形式。1970 年,IBM 的研究员 Edgar Codd 提出了一个天才的方案——关系模型(Relational Model)

这个模型极为简单优雅:所有数据都放在”表”里,用集合论的运算来操作数据。 今天几乎所有主流数据库(MySQL、PostgreSQL、Oracle、SQL Server)都基于这个模型。

🏫 类比:用集合论做菜

假设你有一个冰箱(数据库),里面有各种食材(数据)。

没有关系模型 → 你要自己翻冰箱,一个个看,把需要的找出来。

有关系模型 → 你只需要说”给我拿冷藏室里所有的鸡蛋”(选择)、“只要鸡蛋的生产日期列”(投影)、“把鸡蛋和西红柿搭配在一起”(连接)。

关系代数的本质就是:用集合运算来操作数据


📊 关系(Relation)就是”表”

关系模型的核心概念极简单:

关系(Relation) = 一张有行有列的表(Table)

学生关系(Students):
┌──────┬────────┬────┬───────────┐
│ 学号  │ 姓名   │ 年龄 │ 班级       │
├──────┼────────┼────┼───────────┤
│ 001   │ 张三   │ 20  │ 计科1班    │
│ 002   │ 李四   │ 21  │ 计科2班    │
│ 003   │ 王五   │ 19  │ 计科1班    │
└──────┴────────┴────┴───────────┘

每个”关系”有一个名字(比如 Students),每一列有列名(学号、姓名、年龄、班级),每一行是一条具体记录。

关系模型的三个要点:

  1. 每一列是原子的(Atomic)——每个单元格只能存一个值,不能是一个列表。比如”班级”列只能写”计科1班”,不能写”计科1班、计科2班”
  2. 没有重复行——关系是个集合,集合里没有重复元素
  3. 行的顺序不重要——换个顺序,还是同一个关系

🔢 关系代数——操纵数据的”数学语言”

关系代数(Relational Algebra)是用集合运算来操作关系的一套符号系统。它定义了8 种基本运算,但常用的只有 3 种。

为什么需要关系代数?

因为 SQL 是给”人”看的——它用英语单词(SELECT、FROM、WHERE),理解起来直观。但计算机需要更底层的、没有歧义的数学表示。关系代数就是这个”中间层”:

你的 SQL 查询

关系代数表达式(优化器在这里做优化)

执行计划(计算机真正执行)

① 选择(Selection)——选行

符号:σ(sigma,希腊字母 σ)

选择操作从关系中选出满足条件的行

σ年龄 > 20(Students)

结果:
┌──────┬────────┬────┬───────────┐
│ 002   │ 李四   │ 21  │ 计科2班    │
└──────┴────────┴────┴───────────┘

SQL 对应:SELECT * FROM Students WHERE age > 20

② 投影(Projection)——选列

符号:π(pi,希腊字母 π)

投影操作从关系中选出指定的列

π姓名, 班级(Students)

结果:
┌────────┬───────────┐
│ 姓名    │ 班级       │
├────────┼───────────┤
│ 张三    │ 计科1班    │
│ 李四    │ 计科2班    │
│ 王五    │ 计科1班    │
└────────┴───────────┘

SQL 对应:SELECT 姓名, 班级 FROM Students

③ 连接(Join)——合并表

符号:(bowtie,领结符)

连接操作把两个关系按条件合并成一个新关系。

Students ⋈学号=StudentID Enrollments

把学生表和选课表按"学号匹配"合并:
学号│姓名│年龄│班级│课程号│成绩
────────────────────────────
001 │张三│ 20 │计科1班│ CS101 │ 85
001 │张三│ 20 │计科1班│ CS102 │ 92
002 │李四│ 21 │计科2班│ CS101 │ 78

SQL 对应:SELECT * FROM Students JOIN Enrollments ON Students.学号 = Enrollments.StudentID

连接是关系代数中最强大的操作——它让你能把分散在不同表中的信息”重新组合”起来。


🧩 用关系代数表达完整查询

假设我们想查**“所有选了’数据结构’这门课的学生姓名”**:

π姓名( 
    σ课程名='数据结构'( 
        Students ⋈ Enrollments ⋈ Courses 
    ) 
)

执行过程:

  1. 连接:把学生表、选课记录表、课程表按关联条件合并
  2. 选择:只保留课程名为”数据结构”的行
  3. 投影:只要姓名这一列

这就是 SQL 在底层做的事——你的每个 SQL 查询,数据库都会先转换成关系代数表达式,再做优化和执行。


📋 其他关系代数运算

运算符号含义SQL 对应
合并两个关系的所有行UNION
在关系 A 但不在关系 B 的行EXCEPT
同时在 A 和 B 中的行INTERSECT
笛卡尔积×A 的每行和 B 的每行组合CROSS JOIN
重命名ρ给关系或列改名AS

并和差的一个实际例子

两个班各自有学生名单:

计科1班(学号│姓名)    计科2班(学号│姓名)
001│张三               004│赵六
002│李四               005│钱七
003│王五               006│孙八

计科1班 ∪ 计科2班        → 全部6个学生(并集)
计科1班 − 计科2班        → 张三、李四、王五(只在1班的学生)

🗺️ 从 ER 图到关系模型的转换

现在你可以理解如何把 ER 图转换成关系模型了——这就是”数据库设计”从概念到实现的关键一步:

ER 模型关系模型
实体 →关系(表)
属性 →
主键 →主键列
关系 1:N →在 N 端加外键
关系 M:N →新建一张中间表,加两个外键

例子: 上一节的选课系统 ER 图转成关系模型:

Students(学号, 姓名, 年龄, 班级)
Courses(课程号, 课程名, 学分)
Enrollments(学号, 课程号, 成绩)  ← 中间表,有两个外键
Teachers(工号, 姓名, 职称)

多对多关系(M:N)为什么需要中间表? 因为一张表的”行”没法直接对应多行另一张表的”多行”——中间表的每一行恰好表示”一个学生选了一门课”这一个关系,完美化解 M:N。


📝 小结

概念一句话
关系(Relation)一张有行有列的表,是关系模型的基本单位
选择(σ)选出满足条件的行(WHERE)
投影(π)选出指定的列(SELECT 列)
连接(⋈)按条件合并两个关系(JOIN)
关系代数SQL 的数学基础,数据库优化器用它表示查询

💡 重要理解:关系代数看起来像是”数学课上的东西”,但它是每个 SQL 查询在数据库内部被执行的真实方式。理解了关系代数,你就真正理解了 SQL”为什么这么设计”。

为什么先学这个? 关系代数是 SQL 的理论基础。掌握了关系模型的思维方式,下一步就可以开始真正写 SQL——SQL 基础(DDL, DML)