关系头与关系体
定义 2.4 把关系拆成关系头和关系体,关系头是不变的属性名集合,关系体是随数据变化的内容。

关键术语
重 点
图上的两个气泡“不变”和“可变”是这一页的全部要点。关系头就是第 1 章讲的表头,关系体就是表体。这个拆分是下一节关系模式的伏笔,关系模式描述的正是关系头。
打个比方
一张报名表的空白模板是关系头,收上来的一叠填好的表是关系体。模板一年印一次,填好的表天天在增加。
想一想
给学生表加一列“手机号”,改的是关系头还是关系体?
定义 2.4 把关系拆成关系头和关系体,关系头是不变的属性名集合,关系体是随数据变化的内容。

图上的两个气泡“不变”和“可变”是这一页的全部要点。关系头就是第 1 章讲的表头,关系体就是表体。这个拆分是下一节关系模式的伏笔,关系模式描述的正是关系头。
一张报名表的空白模板是关系头,收上来的一叠填好的表是关系体。模板一年印一次,填好的表天天在增加。
给学生表加一列“手机号”,改的是关系头还是关系体?
关系头对应表结构,关系体对应数据本身,加一条数据是往关系体里放,改取值区间是在改关系头。

Heading 是表单的空白模板,写明第 1 格填姓名只能中文,第 2 格填性别只能男或女,第 3 格填年龄 0 到 150。Body 是学生递交的表单叠在一起。今天加一条数据,是往 Body 里多放一张表单。变更年龄的允许区间,是在改 Heading,结构变化影响全局。
在 MySQL 里,Heading 对应 CREATE TABLE 语句里写的列名、类型和约束,Body 对应 INSERT 进去的每一行。第 5 章会动手写这两种语句,这一页先把它们对应到数学上的关系头和关系体。
把“性别”一列的允许值从男、女改成男、女、未填,动的是哪一部分?
五条性质:列同质、列名互异、列序无关、行序无关、不允许重复元组。

列同质,因为一列的值都来自同一个域。列名互异,因为两列可以同域,只能靠名字区分。列序无关和行序无关,因为关系是集合,集合里的元素没有先后。不允许重复元组,因为集合里没有相同的元素。交换两列时要连同列名一起换,只换值不换名,得到的是另一张表。
| 姓名 | 性别 | 年龄 |
|---|---|---|
| 刘杨 | 男 | 40 |
| 石丽 | 女 | 26 |
| 顾伟 | 男 | 32 |
把学生表按成绩从高到低重新排一遍,它还是原来的关系吗?
每个分量必须是不可再分的数据项,表中不能再套表,满足这一条的关系叫规范化关系。

左表“籍贯”一列下面又分省和市两级,这就是表中有表。拆成“省”和“市/县”两列之后,每个格子里只有一个值,就规范化了。这是第 12 章第一范式的雏形,那一章会讲更多层次的规范化。
快递地址整个写在一个格子里,按省统计就要人工拆开。分成省、市、街道三格,一格一个值,统计就是一句话的事。
C 的“联系方式”下面又分电话和邮箱两项,一个格子里装了两个值,属于表中有表。把它拆成电话、邮箱两列就规范化了。
“姓名”一列里写着“张三(班长)”,算不算表中有表?
三道练习:说出 CourseSelect 的度和各属性的域,把关系头和关系体分开写,再想想 term 写成 VARCHAR 会出什么问题。

度是 3,因为有三个属性。studentId 的域是学号集合,courseId 的域是课程号集合,term 的域是固定的两个值 {2025春,2025秋}。三条元组例如 (10001,DB201,2025春)、(10002,DB201,2025春)、(10001,AI101,2025秋)。关系头是三个属性名连同各自的域,关系体是这三行。
三道题对应三条定义:度对定义 2.3,域对定义 2.1,关系头与关系体对定义 2.4。第三题问的是域没有写进类型会怎样,答案在第 20 页,它引出下一节的关系模式和第五节的完整性。
term 这个属性,你会让它允许填什么值?
度是 3,三个属性的域分别是学号集合、课程号集合和固定的学期枚举,元组是三个分量按顺序排好的小括号。

域可以是很大的集合,学号集合、课程号集合都是,也可以是只有两个值的枚举,学期就是。三条元组里 10001 出现了两次不算重复,因为整行不同,判断重复看的是整个元组。三个分量的顺序和属性的顺序一致,先学号再课程号再学期。
火车票有车次域、日期域、座位域,一张票是一个元组。同一个人买两张票,只要有一个分量不同,就是两个不同的元组。
(10001,DB201,2025春) 再插一次,会发生什么?
关系头写成 CREATE TABLE,每个属性一行,域用类型和 ENUM 表达,关系体就是右边那三行数据。

VARCHAR(10) NOT NULL 是学号的域,最多十个字符且不能空。ENUM('2025春', '2025秋') 把学期的域写死成两个值。PRIMARY KEY 把三列合起来定为主码,体现同一学生同一课程同一学期只选一次。两条 FOREIGN KEY 说明学号和课程号必须在学生表和课程表里存在。后两条是第四、五节的内容,第 5 章会动手写。
把 term 的 ENUM 改成 VARCHAR,关系头变了吗?
term 写成 VARCHAR 而不是枚举,等于把域的规则丢掉,六种数据质量问题会跟着进来。

域就是规则,规则不写进类型和约束里,脏数据就会进来。六条里最要紧的是第三条,“2025春”和“2025 春”会被当成两个学期,同一人同一课同一学期就能出现两条记录,主码的唯一性被绕开了。其余几条是它的连锁反应:分组失真、查询漏数、清洗成本高、排序混乱。
表单上的“学期”一栏如果让人手填,会收到 2025春、2025 春、春2025 各种写法。改成只有两个选项的下拉框,问题就没了。ENUM 就是数据库里的下拉框。
你填过的哪种表单,让你觉得应该改成下拉框?