简介:这份《数据库关系代数习题.pdf》面向正在学习数据库系统原理的高校学生与备考人员,聚焦关系代数这一查询语言核心考点,帮助读者通过大量练习掌握选择、投影、连接、除等运算的实际应用。资源为单个PDF文件,压缩包约304KB,内容以习题与参考答案为主,涵盖学生、课程、学习等经典关系模式下的多类查询场景。题目从检索特定专业学生课程信息、筛选高分课程成绩,到求解不学某课程的学生、无不及格课程的学生,再到选修全部课程、至少选修李强全部课程等较复杂的除法与差集运算,均给出对应的关系代数表达式及简要解释。此外还涉及厂家、产品、工程、供货等SPJ数据库的供货查询,以及E-R模型设计与关系模式转换等综合练习。目前已有2805人学习下载,适合作为课堂同步练习、期末复习或考研备考的专项训练材料,便于读者对照题目与答案梳理运算思路、查漏补缺。
1. 从一份「数据库关系代数习题.pdf」说起:为什么刷题总在 π、σ、⋈ 上翻车
很多人第一次打开数据库关系代数习题.pdf,心态都是「这不就是集合运算加几个希腊字母」。真做起来才发现,选择 σ、投影 π、连接 ⋈ 单独看都懂,一旦组合成嵌套表达式,或者要求把一段 SQL 反推成关系代数,就立刻卡壳。更麻烦的是,习题里的题干往往只给几张表,让你写出「查询选修了全部课程的学生」这类表达式,除法和外连接一混进来,正确率断崖式下跌。
这份习题集真正训练的不是背符号,而是把「数据库增删改查」背后的集合语义翻译成可推导的表达式。它适合三类人:正在准备数据库课程设计的学生、要应付数据库面试题里关系代数推导的求职者、以及想真正理解查询优化器在做什么的工程师。关系代数是 SQL 的数学底座,理解了它,你再看执行计划、再看数据库优化,就不是玄学。
下面按「先立住理论、再动手推导、最后避坑」的顺序,把这份习题集拆成可复现的解题流程。每一章都落到能直接抄的推导步骤和验证方法,而不是空谈概念。
2. 关系代数五大基本运算:把符号翻译成可手推的步骤
关系代数的所有表达式,最终都能归约到五个基本运算:并 ∪、差 −、笛卡尔积 ×、选择 σ、投影 π。其余的交 ∩、连接 ⋈、除法 ÷ 都是派生运算。习题集里 80% 的题,卡点都在「不知道从哪个基本运算开始拆」。
2.1 选择 σ 与投影 π:先筛行还是先筛列
选择 σ 是按条件筛行,投影 π 是按属性筛列。看起来简单,但顺序不同结果和效率差很多。习题里常见陷阱是:题目要求「查询年龄大于 20 的学生的姓名」,正确写法是先 σ 再 π:
π 姓名 (σ 年龄>20 (学生))如果反过来写成 σ 年龄>20 (π 姓名 (学生)),投影后年龄列已经没了,条件无法求值,直接错。这是习题集里最高频的翻车点。
我一般教人的判断口诀:条件里出现的列,必须在投影之前还存在。所以凡是带条件的查询,σ 一定在 π 的内层。参数上要注意,σ 的下标是布尔表达式,可以带 ∧、∨、¬,习题里经常用 ∧ 连接多条件,别漏写括号导致优先级出错。
2.2 笛卡尔积 × 与连接 ⋈:为什么习题答案总多一列
笛卡尔积把两张表所有行两两组合,列数是两表之和。连接 ⋈ 是在笛卡尔积基础上加选择条件。习题里让你写「查询每个学生及其选修课程」,标准写法是:
π 学生.学号, 姓名, 课程号 (学生 ⋈ 选课)这里 ⋈ 默认是等值连接,连接条件是 学生.学号 = 选课.学号。很多人直接写 学生 × 选课 然后忘了加 σ,结果列数爆炸、行数爆炸,答案自然错。
自然连接 ⋈ 会自动去掉重复的同名列,这是习题里最容易混淆的地方。等值连接保留两列学号,自然连接只留一列。题目如果说「自然连接」,你就不能手动写连接条件;如果说「等值连接」,就必须写清楚。
| 运算 | 符号 | 是否去重列 | 习题常见问法 |
|---|---|---|---|
| 笛卡尔积 | × | 否 | 所有组合 |
| 等值连接 | ⋈ 条件 | 否 | 按某列相等连接 |
| 自然连接 | ⋈ | 是 | 同名属性自动匹配 |
2.3 并、差、交:集合运算的三个前提
并 ∪、差 −、交 ∩ 要求两个关系属性个数相同、对应属性域相同,这叫并相容性。习题里经常给两张结构不同的表让你做并运算,正确做法是先投影对齐属性再并。比如「查询选修了 C1 或 C2 的学生」:
π 学号 (σ 课程号='C1' (选课)) ∪ π 学号 (σ 课程号='C2' (选课))注意两边投影出的属性名要一致,否则并运算在严格定义下不合法。差运算 − 常用来表达「选修了 C1 但没选修 C2 的学生」,交 ∩ 则表达「两门都选」。这三个运算的坑在于:习题答案有时用 ∪ 有时用 ∨,你要能看出它们是等价的。
2.4 用一张最小表跑通五个基本运算
拿习题集里最常见的三张表练手:学生(学号,姓名,年龄)、课程(课程号,课程名)、选课(学号,课程号,成绩)。先建最小数据集,手动推一遍:
学生: {S1,张三,20}, {S2,李四,22} 课程: {C1,数据库}, {C2,操作系统} 选课: {S1,C1,90}, {S1,C2,85}, {S2,C1,70}然后逐题验证:查询年龄大于 20 的姓名 → π 姓名(σ 年龄>20(学生)) = {李四}。查询选修 C1 的学生姓名 → π 姓名(学生 ⋈ σ 课程号='C1'(选课)) = {张三,李四}。每一步都手推,比看答案有效得多。
提示:习题集里凡是带「全部」「至少」「没有」的题,先别急着写表达式,先想清楚它对应除法还是差运算,这是后面第 4 章的重点。
3. 从 SQL 反推关系代数:习题集里最值钱的逆向训练
习题集后半部分大量出现「给出 SQL,写出等价关系代数」的题。这类题才是真正锻炼查询思维的地方,因为工作中你更多是反过来:先有需求,再决定写 SQL 还是推代数。逆向训练能让你看清 SQL 每个子句对应哪个运算。
3.1 SQL 子句到关系代数的映射表
把映射关系记牢,反推就是查表填空:
| SQL 子句 | 关系代数 | 说明 |
|---|---|---|
| FROM 单表 | 直接引用关系 | 基表或视图 |
| FROM 多表 | × 或 ⋈ | 有连接条件用 ⋈ |
| WHERE | σ | 筛选行 |
| SELECT 列 | π | 投影列 |
| DISTINCT | δ | 去重,习题常省略 |
| GROUP BY | γ | 分组聚合 |
| HAVING | σ | 对分组结果筛选 |
| ORDER BY | τ | 排序,习题少考 |
反推时按「FROM → WHERE → SELECT」的顺序翻译,因为 SQL 逻辑执行顺序就是先定数据源、再筛行、再选列。习题里如果 SELECT 里有聚合函数,就要用 γ 而不是 π。
3.2 一个完整反推示例:带 GROUP BY 的查询
题目:查询每个学生的选课门数,输出学号和门数。SQL 是:
SELECT 学号, COUNT(*) AS 门数 FROM 选课 GROUP BY 学号;对应关系代数用分组聚合 γ:
学号 γ COUNT(课程号) → 门数 (选课)γ 的下标左边是分组属性,右边是聚合函数及结果属性名。习题里常考 COUNT、SUM、AVG、MAX、MIN 五个聚合。注意 γ 之后如果要再筛选,比如「门数大于 2」,就要在外面套一层 σ:
σ 门数>2 (学号 γ COUNT(课程号) → 门数 (选课))这里有个易错点:HAVING 对应的是 γ 外层的 σ,不是 WHERE 的 σ。WHERE 在分组前筛行,HAVING 在分组后筛组,习题集里专门有一组题考这个区别。
3.3 嵌套子查询怎么翻译成代数
SQL 里的 IN、EXISTS 子查询,翻译成关系代数通常用半连接或差运算。比如「查询选修了 C1 的学生」:
SELECT 学号 FROM 学生 WHERE 学号 IN (SELECT 学号 FROM 选课 WHERE 课程号='C1');等价代数:
π 学号 (学生 ⋈ (σ 课程号='C1' (选课)))如果是 NOT IN,就变成差运算:
π 学号 (学生) − π 学号 (σ 课程号='C1' (选课))反推时记住:IN 对应连接或半连接,NOT IN 对应差,EXISTS 对应半连接,NOT EXISTS 对应除法或差。习题集里 NOT EXISTS 的题最难,因为它往往等价于「全部」语义,需要用到除法。
3.4 用执行顺序验证你的反推结果
写完代数表达式后,别急着对答案。先按「最内层先算」的顺序手动执行一遍,看行数和列数是否符合预期。比如上面 NOT IN 的例子,先算 σ 得到选修 C1 的学号集合,再用全体学号减去它,剩下的就是没选 C1 的。如果结果里出现了不该有的学号,说明连接条件或投影列写错了。
我一般会让学生把每步中间结果写在小表上,像调试代码一样单步走。习题集答案只给最终表达式,但真正让你进步的是中间过程。这一步花的时间,比刷十道题都值。
4. 除法与「全部」语义:习题集里最容易劝退的一类题
「查询选修了全部课程的学生」「查询至少选修了学生 S1 所选全部课程的学生」——这类题在习题集里出现频率极高,也是挂科重灾区。它们的共同点是含「全部」「至少」这种全称量词,标准解法是除法 ÷,或者用差运算等价改写。
4.1 除法 ÷ 的定义与适用条件
关系 R(X, Y) ÷ S(Y) 的结果是 X 上的关系,包含所有满足「对 S 中每个 Y 值,R 中都有对应 (x, y)」的 x。用习题语言说:R 是被除关系,S 是除数关系,结果是「全都能配上」的那些 x。
适用条件:S 的属性集必须是 R 属性集的真子集。习题里常见形式是 选课(学号, 课程号) ÷ 课程(课程号),结果是选修了全部课程的学号。
π 学号, 课程号 (选课) ÷ π 课程号 (课程)注意被除关系要先投影出 (学号, 课程号) 两列,去掉成绩列,否则属性集不匹配,除法不合法。这是习题集里第一个坑。
4.2 用差运算等价改写除法
很多习题集要求「不用除法,用基本运算表示」。除法的等价改写是:
R ÷ S = π X (R) − π X ((π X (R) × S) − R)翻译成人话:先假设所有 x 和所有 y 都配上了,减去实际没配上的,剩下的就是全配上的。以「选修全部课程」为例:
π 学号 (选课) − π 学号 (π 学号 (选课) × π 课程号 (课程) − π 学号,课程号 (选课))这个表达式看着吓人,但拆开就是三步:全体学号 × 全体课程号得到「理论上所有组合」,减去实际选课记录得到「没选的组合」,再投影出学号,最后从全体学号里减掉。习题集里这类题一定要动手写一遍,光看会觉得自己懂了,一写就错。
4.3 「至少选修了 S1 全部课程」的推导
这是除法的变体,除数不是全部课程,而是 S1 选的课程。步骤:
S1课程 = π 课程号 (σ 学号='S1' (选课)) 结果 = π 学号, 课程号 (选课) ÷ S1课程如果要排除 S1 本人,最后再减掉:
结果 − {S1}习题集里经常加一句「不包括 S1 自己」,很多人漏掉这个差运算。这类题的坑在于:除法的被除关系必须是「学号,课程号」两列,不能带成绩,否则属性集对不上。
4.4 用 NOT EXISTS 双重否定理解「全部」
SQL 里「全部」的标准写法是双重 NOT EXISTS:
SELECT 学号 FROM 学生 WHERE NOT EXISTS ( SELECT * FROM 课程 WHERE NOT EXISTS ( SELECT * FROM 选课 WHERE 选课.学号 = 学生.学号 AND 选课.课程号 = 课程.课程号 ) );翻译成关系代数就是除法。理解这个双重否定,比死记除法公式有用得多:外层「不存在一门课」,内层「不存在这个学生选这门课的记录」,合起来就是「所有课这个学生都选了」。习题集里如果考 NOT EXISTS 到代数的转换,你就按这个逻辑一步步拆。
注意:除法结果可能为空集,这是合法结果,不是算错。习题集里有些题答案就是空关系,别以为自己推错了。
5. 避坑与排查:关系代数习题里 5 个高频翻车点
这一章专门收习题集里反复出现的错误。每条按「现象 → 原因 → 解决」写,都是血泪经验。
5.1 现象:投影后条件列消失,表达式无法求值
原因:把 σ 写在了 π 外层,投影已经把条件列删掉了。解决:记住「条件列必须在投影前存在」,σ 永远在 π 内层。检查方法:从最内层往外读,看每个 σ 引用的列在当前层是否还在。
5.2 现象:连接结果列数比预期多一列
原因:该用自然连接 ⋈ 的地方用了等值连接 ⋈ 条件,同名列没去掉。解决:题目说「自然连接」就用 ⋈ 不带条件,说「等值连接」才写条件。检查方法:数一下结果属性个数,和题目要求的输出列对比。
5.3 现象:并运算报错或结果属性名混乱
原因:两个关系属性个数或域不一致,违反并相容性。解决:先各自投影对齐属性再并,并保证属性顺序一致。检查方法:把两个操作数的属性列表写出来逐列对比。
5.4 现象:「全部」类题目写成连接,结果少了学生
原因:用连接只能表达「选了某门课」,表达不了「选了全部课」。解决:识别全称量词,改用除法或双重差运算。检查方法:如果题目里有「全部」「所有」「至少」,先想除法。
5.5 现象:HAVING 条件写进了 WHERE 位置
原因:混淆了分组前筛行和分组后筛组。解决:WHERE 对应 γ 内层的 σ,HAVING 对应 γ 外层的 σ。检查方法:看条件里有没有聚合函数,有聚合就在外层。
6. 把习题集变成可验证的训练系统:我的三个习惯
刷完习题集不等于掌握,能自己出题、自己验证才算。我一般用三个习惯把这份 PDF 用透。
第一个习惯是建最小数据集手推。每道题先在纸上建三五行的小表,手动执行每一步运算,把中间结果写出来。这比对着答案看有效十倍,因为你能看到哪一步行数或列数不对。习题集里很多题的数据是抽象的,自己造具体数据反而更容易发现错误。
第二个习惯是SQL 与代数双向翻译。拿到代数表达式,写出等价 SQL;拿到 SQL,写出代数。两个方向都练,才能真正理解映射关系。下面这个对照表可以当检查清单:
| 代数 | SQL | 验证要点 |
|---|---|---|
| σ | WHERE | 条件列是否还在 |
| π | SELECT | 是否去重 |
| ⋈ | JOIN | 连接列是否重复 |
| ÷ | NOT EXISTS 双重 | 是否含「全部」 |
| γ | GROUP BY | 聚合函数位置 |
第三个习惯是用真实数据库验证。把习题里的表建到本地数据库里,用 SQL 跑一遍,再对照代数表达式的手推结果。如果两者不一致,一定是某一方错了。这一步能帮你发现习题答案本身的笔误,也能让你对「数据库优化」里优化器为什么改写查询有直观感受。
最后一个技巧:习题集里凡是做错的题,别只记正确答案,把错误原因归类到第 5 章那五类里。错三次以上的类型,就是你真正的薄弱点。我自己当年在除法上栽了无数次,后来逼着自己把每道除法题都用差运算重写一遍,才彻底过关。关系代数这东西,看会不算会,手推对了才算。希望帮到你。
本文还有配套的精品资源,点击获取