简介:《数据库系统概论(第五版)》(王珊版)课后习题答案文档,专门面向学习数据库原理的本科生、考研复习者及自学者,可对照教材逐章检验理解程度。资源为单个doc文档,大小约588KB,内容覆盖第2章关系数据库、第3章关系数据库语言SQL等章节的详细解答,既适合平时作业订正,也适合考前集中复习。文档并非简单罗列答案,而是结合教材内容梳理了重要知识点,包括关系模型的三个组成部分、关系数据语言的三种分类及共同特点、实体完整性与参照完整性规则、关系代数五种基本运算及其相互表达,以及SQL语言“综合统一、高度非过程化、面向集合操作”等五大特点。针对典型习题,文中给出了完整求解过程与SQL语句实例,例如用π、σ等关系代数运算符完成SPJ数据库查询,用CREATE TABLE语句建立S、P、J、SPJ四个表并实现嵌套查询,同时还辨析了等值连接与自然连接的区别,能够帮助读者在对照参考答案时理解每一步的推导依据,快速定位自身薄弱环节。当前已有1723人学习下载,适合作为数据库原理课程的配套练习资料、期末突击或考研复习的补充材料。
1. 这份答案文档能帮你什么:先别急着抄,先搞清楚它值不值得信
期末复习到了刷题阶段,手边正好有一份某经典教材第 5 版的课后答案文档,格式还是 .doc 的老古董。多数人的第一反应是打开、对照、抄完交差,但真正做过一遍的人都会有一个同样的感受:答案文档最大的价值不在于给你标准结果,而在于它逼着你把错题晾在台面上,逼着你承认自己对某个知识点是模糊的。这份文档覆盖的内容集中在关系代数、范式分解、SQL 查询、事务并发这几个老大难章节,而恰恰是这些章节,答案里也经常藏着让人挠头的“版本差异”和“印刷错误”。这篇笔记就围绕着这份答案文档展开,讲清楚它适合谁、怎么用它做自我验证、哪些题必须动手搭环境跑一遍,以及哪几类题你得留个心眼,不能全信。适合期末冲刺、考研复习、转行自学三类读者,每类人的用法还不一样。
2. 先摸清第 5 版的章节地图:答案文档覆盖了哪些题,难点分布在哪
2.1 章节结构与习题类型对照
用这份答案文档之前,先得知道这本书把知识点放在了哪几章、课后题大概长什么样。第 5 版的章节结构沿用了数据库教材最常见的组织方式:先说数据模型和数据库系统结构,再进关系模型、SQL、安全性完整性,然后上关系数据理论(范式),接着是数据库设计、查询优化、事务、恢复、并发控制,最后是数据库新技术展望。
课后习题的题型可以分成四类,每一类的检查方式完全不同。
| 章节主题 | 常见题型 | 答案验证方式 |
|---|---|---|
| 绪论、数据模型 | 选择题、简答题 | 对照教材原文,查概念定义 |
| 关系模型与关系代数 | 应用题(求表达式、求结果) | 手工推演 + 转成 SQL 跑真实数据库 |
| SQL 语言 | 写 SQL 语句 | 搭本地 SQLite 环境直接执行 |
| 安全性、完整性 | GRANT/REVOKE 语句、约束设计 | 语法对照 + 在数据库里实测 |
| 关系数据理论 | 函数依赖判断、范式级别判定、模式分解 | 手工推演为主,可写脚本辅助 |
| 数据库设计 | ER 图设计、ER 图转关系模式 | 手工核对设计规范 |
| 查询优化 | 代数优化规则、代价估计 | 手工推演 + EXPLAIN 对照 |
| 事务、恢复、并发控制 | ACID 概念题、日志分析、调度判定 | 手工推演为主 |
文档里最常见的是前两类题的标准解,后面两类因为涉及推演过程,不同版本教材答案经常有出入。
2.2 全书公认最难的三块内容,答案文档也在这里最容易出歧义
第一块是关系数据理论,也就是函数依赖、候选键推导、范式级别判定、模式分解。难在它本质上是形式化的逻辑推理,一步错步步错。答案文档里给出的分解结果,经常出现“无损连接成立但依赖保持不成立”这种让人抓狂的情况。
第二块是并发调度。判断一个调度是否冲突可串行化,要看冲突操作对的顺序能否通过交换非冲突操作来重排。这个交换过程只可意会不可言传,答案文档通常只给结论不給推导过程,你对了答案也不知道自己错在哪一步。
第三块是 SQL 中的复杂查询,尤其是涉及子查询、聚合函数、EXISTS/NOT EXISTS 的题目。这类题的答案正确与否,其实跟具体数据库方言有关系,同一个查询在 SQLite、某个开源数据库、商业数据库里跑出来的结果可能一致,但写法上会有细微差异。答案文档只给一个标准解,不考虑方言差异,这也是很多人对答案怎么都对不上的原因之一。
2.3 为什么先做题再翻答案,而不是边做边看
很多人拿到这份答案文档的第一件事是通读一遍,感觉知识点都会了,合上文档又全忘了,这是典型的“答案熟悉度错觉”。眼睛看答案和手写答案,大脑的加工深度差得非常多。我一般要求学生这么做:把每章的课后题先独立做一遍,哪怕是瞎蒙也要写出一个结果;做不出来的题在题号旁边画个问号,跳过;这一遍完全不碰答案文档。
做完第一遍,再打开答案文档逐题对照。对照时不只要看结果对不对,更要看自己的推演路径跟答案的推演路径是不是同一个思路。很多应用题的结果是对的,但走的路径绕了远路,考试时时间一紧就容易翻车。这个环节会非常不舒服——你会发现一半以上的题你自己写的步骤是不完整的,但这恰恰就是答案文档真正的用法:它不是参考书,是照妖镜。
3. 三遍刷题法:怎么把一份答案文档用出网课的效果
3.1 第一遍:按章独立做题,答案文档全程不打开
把课后题当成闭卷考试来对待,这个动作不能省。我自己复习时有一个习惯:在笔记本上把每道题的题号抄下来,右边留三栏,分别写“我的答案”“标准答案”“差异分析”。第一遍只填第一栏,遇到完全没思路的题就画一个大大的叉,然后用便签标记是哪一章的哪个知识点没搞懂。
这个阶段不要在意正确率。我见过不少人第一遍做题错了一半就开始焦虑,其实完全没必要——错题才是你复习的地图。范式分解题不会做,说明函数依赖的闭包计算没吃透;SQL 子查询写不出来,说明你对 EXISTS 和 IN 的语义差异还不敏感。这些信号比分数值钱得多。
第一遍做题的时间控制也很重要。这本书的课后题量大,全部硬啃一遍可能要花三到四周,每天一两小时即可。不要试图一天刷完一章,大脑消化概念需要时间,特别是范式推理这类抽象内容,隔天再回头看昨天做错的题,往往会有新的理解。
3.2 第二遍:对照答案,把错误归成三类
打开答案文档,逐题对照,这一遍在笔记本的第二栏抄答案,第三栏写差异分析。注意,差异分析不要只写“错了”,要写清楚错在哪里。我习惯把错误归成三类:概念理解错误、推演步骤跳跃、结果对但过程绕远。
概念理解错误是第一类,也是最严重的一类。比如把 3NF 的判定条件搞混,以为“消除了非主属性对候选键的传递依赖”就万事大吉,结果漏了“函数依赖左边必须是超键”或者“要么是无关属性”这后半句。这种错误必须回教材重新读定义。
推演步骤跳跃是第二类。这类错误在关系代数和日志恢复题里最常见。答案里三步能写完的推演,你两步就跳过去了,中间那步恰好藏着关键的知识点。
结果对但过程绕远是第三类,最隐蔽。你以为自己对了,其实只是误打误撞。比如 SQL 里同一个查询用嵌套子查询能写出来,但用连接加聚合更清晰高效,后者才是教学上想考的点。
3.3 第三遍:对存疑题做交叉验证,不能只信一份答案
第二遍对照完之后,笔记本上会留下几个争议题——你的答案和文档答案不一致,而且你反复检查觉得自己没算错。这种情况不要急着认定答案错了,也别急着怀疑自己,先做交叉验证。
第一步是回教材正文找依据。教材里通常有对应的例题,看例题的完整推演过程,再用同样的方法套到习题上。第二步是找其他练习题的同类型题做对比,看看是不是同一类题目的解法在这本书里前后有矛盾。第三步,也就是最有说服力的方式,是把能实操的题直接丢进数据库或脚本里跑一遍,用机器的执行结果来裁决。
这三步走完,如果确实发现答案文档有误,我建议你在笔记本的题号旁边做一个醒目的标记,比如画一个圈,再在旁边写“文档答案存疑,按教材例题推演应为……”。这些事情做完,这份答案文档才真正变成了专属于你自己的学习资产。
4. 用本地 SQLite 验证 SQL 题答案:搭建最小验证环境
4.1 为什么选 SQLite:零配置文件,一条命令进交互模式
这本书 SQL 章节的课后题,基本上都基于学生选课、员工部门、供应商零件这类经典教务场景。验证这些题的答案,不需要装重量级的数据库服务端,SQLite 是最合适的工具:不需要配置端口、不需要启动服务、不需要账号密码,而且主流的 Unix 系统都内置了命令行工具。
在 Debian 系的系统上,装好之后直接在终端敲 sqlite3 就能进入交互模式。Windows 用户可以从官方渠道下载免安装的二进制文件,下载后解压到任意目录,把 sqlite3.exe 的路径加进环境变量即可。macOS 自带 SQLite,无需安装。
# Debian/Ubuntu 系列安装 SQLite 命令行工具 sudo apt-get install sqlite3 # 启动一个临时数据库并进入交互模式 sqlite3 :memory: # 如果已有习题库文件,直接打开 sqlite3 exercise.db参数说明::memory:表示使用纯内存数据库,进程退出后数据全部消失,适合做临时验证。exercise.db是一个持久化文件数据库,建好的表和数据会保留在磁盘上,适合做完一题关闭下次继续。
4.2 建表与插入数据:按教材场景还原一张选课表
验证 SQL 答案之前,先把教材习题对应的表结构和样例数据建好。以最经典的选课场景为例,三张表:学生表、课程表、选课表。下面这段 SQL 以教材习题的标准结构为蓝本,字段名用英文便于在 SQLite 里直接执行。
-- 学生表:学号、姓名、系别、年龄 CREATE TABLE student ( sno TEXT PRIMARY KEY, sname TEXT, sdept TEXT, sage INTEGER ); -- 课程表:课程号、课程名、先行课、学分 CREATE TABLE course ( cno TEXT PRIMARY KEY, cname TEXT, cpno TEXT, ccredit INTEGER ); -- 选课表:学号、课程号、成绩 CREATE TABLE sc ( sno TEXT, cno TEXT, grade INTEGER, PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) );执行完这段建表语句,接下来插入几条样例数据。插数据时要注意先行课字段,比如“数据库原理”的先行课是“数据结构”,cpno 字段填的是先行课的课程号。
INSERT INTO student VALUES ('2001', '张三', '计算机', 20); INSERT INTO student VALUES ('2002', '李四', '计算机', 21); INSERT INTO student VALUES ('2003', '王五', '数学', 20); INSERT INTO course VALUES ('C1', '数据库原理', 'C3', 4); INSERT INTO course VALUES ('C2', '数据结构', NULL, 3); INSERT INTO course VALUES ('C3', '操作系统', 'C2', 4); INSERT INTO sc VALUES ('2001', 'C1', 92); INSERT INTO sc VALUES ('2001', 'C2', 88); INSERT INTO sc VALUES ('2002', 'C1', 78);逻辑说明:这张表结构对应了教材 SQL 章节的多类习题——单表查询、连接查询、嵌套查询、EXISTS 子查询,都能在这个结构上直接演练。字段类型选择上,学号和课程号用 TEXT 而不是 INTEGER,是因为这类编号往往带有前导字符,设计习题时也常出现字母,TEXT 最稳妥。
4.3 用 SQLite 验证典型的嵌套查询题
教材 SQL 章最常考的一类题是“查询选修了全部课程的学生”,标准写法用 NOT EXISTS 双重否定。很多答案文档只给结果不给你执行的验证方法,这里直接把它跑出来。
-- 查询选修了全部课程的学生姓名 -- 思路:不存在一门课程,这个学生没选 SELECT sname FROM student s WHERE NOT EXISTS ( SELECT 1 FROM course c WHERE NOT EXISTS ( SELECT 1 FROM sc WHERE sc.sno = s.sno AND sc.cno = c.cno ) );执行结果会返回“张三”,因为张三选了 C1 和 C2 全部两门课程,而李四只选了 C1。这里的核心逻辑是双重 NOT EXISTS:先固定一个学生,检查课程表里是否找得出一门课该学生没有选课记录,如果找不出,说明该学生选修了全部课程。
参数与语义说明:外层SELECT sname FROM student s是遍历每个学生;内层第一个NOT EXISTS检查“不存在没选的课”;最内层SELECT 1 FROM sc只用到了 EXISTS 的存在性判断,查什么列无所谓,惯例写 1。如果把这个查询改写为用NOT IN,需要注意sc.grade为 NULL 时的语义差异——这里我们设计数据时控制住 NULL 干扰,但实际验证别的题时,NULL 会让你摔得很惨。
4.4 验证聚合与分组题:平均分和最高分不要想当然
分组聚合是另一类高频题。“查询每门课程的平均成绩并按课程号排序”这类题,答案文档的写法基本一致,但你自己跑一遍才能体会到 GROUP BY 和 HAVING 的执行顺序。
SELECT cno, AVG(grade) AS avg_grade FROM sc GROUP BY cno ORDER BY cno;这个查询的结果是一目了然的,但真正容易出问题的是“查询平均成绩大于 80 分的课程号”。很多人会习惯性写成 WHERE AVG(grade) > 80,然后在 SQLite 里直接报错。
-- 正确写法:分组后的条件过滤用 HAVING,不能用 WHERE SELECT cno FROM sc GROUP BY cno HAVING AVG(grade) > 80;逻辑说明:WHERE 在分组前过滤行,HAVING 在分组后过滤组。SQLite 对聚合函数出现在 WHERE 子句中的行为是直接报错,这反而是在帮新手纠错。但某些数据库对这类写法会有不同的容错表现,这也是为什么我强调——SQL 题不能只对答案文档,最终要以真实执行结果为准。
5. 避坑排查:答案文档和你的推演结果不一致,先查这五处
5.1 范式分解翻车:3NF 分解和 BCNF 分解混为一谈
现象:你的分解结果保持了无损连接,答案文档的分解结果保持了依赖;两边看起来都对,但细看发现你的分解丢了一个函数依赖。
原因:3NF 分解算法要求保持函数依赖,BCNF 分解算法只保证无损连接,不保证依赖保持。很多习题答案在要求“无损且保持依赖”时,用的是 3NF 合成法;在某些边界情况下,BCNF 分解无法同时满足依赖保持,习题的标准解就会取 3NF。
解决:做题前先圈出题目里的关键词——“保持函数依赖”对应 3NF 合成法,“无损连接”可能对应 BCNF 分解法。你的分解结果如果丢了依赖,用教材给出的判定算法重新算一遍依赖闭包,再决定改用哪种分解策略。对照答案时分两步验证而不是一步到位,这样能精确定位是第几步分歧。
5.2 SQL 子查询结果对不上:IN 与 EXISTS 在 NULL 面前表现不同
现象:一道“查询没有选修某门课程的学生”的题,你的答案用 NOT IN,文档答案用 NOT EXISTS,两边跑出来结果不一样。
原因:当子查询结果集中出现 NULL 时,NOT IN 的行为是整体返回空集(因为 NULL 参与比较的结果是 UNKNOWN,取反后还是 UNKNOWN),而 NOT EXISTS 逐行检查,NULL 不影响判定逻辑。
解决:先把子查询单独跑一遍,检查结果列里有没有 NULL;如果有且业务语义上不该有,说明题目环境的设计里应该补一个 NOT NULL 约束或过滤条件。更稳妥的做法是在写 NOT IN 的子查询最后加WHERE 列 IS NOT NULL,排除 NULL 干扰后再与文档答案对比。这一步是 SQL 题最常见的“看着答对了实际是错的”场景。
5.3 并发调度题总错:冲突可串行化只看冲突操作对的相对顺序
现象:两个事务 T1、T2 作用在同一个数据项 A 上,你凭直觉认为某个调度不可串行化,但答案说可以,或者反过来。
原因:判断冲突可串行化,只看不同事务对同一数据项的冲突操作对(读写、写读、写写)在调度中的相对顺序是否和某个串行调度一致,而读读操作不算冲突。很多人会额外引入无关操作来比较,把问题搞复杂。
解决:画出事务的操作序列,把所有事务按顺序排列,把属于同一个事务的操作标成同色或同行,然后挑出所有跨事务且针对同一数据项的冲突操作对,比较它们的前后次序是否形成环。有环则不可串行化,无环则可串行化。把这个判定过程写到草稿纸上,再和答案对照,基本不会翻车。
5.4 ER 图转关系模式:1:1 联系的主键放哪边,教科书有固定章法
现象:ER 图里两个实体之间是 1:1 联系,答案文档把 A 实体的主键放进了 B 实体的关系模式,而你的做法刚好相反,两边都被教材例题支持过,不知道听谁的。
原因:1:1 联系转关系模式时,联系本身可以并入任意一端的实体关系模式中,把另一端的主键作为外键属性加进来。教材为了统一,通常在例题里固定写成“并入参与度小的那一边”,但习题答案可能采用了另一种约定。
解决:统一采用“外键加在需要减少冗余的一端”的原则,也就是检查哪一端加外键后关系模式中重复数据更少。如果两端都差不多,就按教材例题的惯例选一端,并在旁边注明这种选择不是唯一的。对照答案时,只要你的函数依赖没有丢失、主外键关系成立,就应该视为可接受答案。
5.5 答案文档版本老化:第 5 版和旧版习题编号错位
现象:你在文档里找第 3 章某道题的答案,翻遍整个文档找不到,或者找到的题目和你手头教材的题干对不上。
原因:市面上流传的这份答案文档,有一些是从旧版本教材的配套答案整理过来的,旧版与新版的章节编排、习题编号存在错位。新版教材可能删了旧版的某道题,新版的某道题又不在旧版答案里。
解决:先看文档开头或尾页有没有“对应教材版本”的说明;如果没有,用题干的关键词在文档内做全文检索,不要按题号找。拿文档里的一道“原题”和你手头的教材正文对照,看是否同源。这种方法虽然笨,但能有效避免你浪费时间在一个根本不存在的答案编号上。
6. 进阶用法:把答案文档做成你自己的错题索引
刷完三遍并完成验证后,这份答案文档就可以退居幕后了。我习惯把每章错题的题号、错误类型、出错的知识点整理成一张索引表,用最简单的 CSV 格式存下来,复习的时候只扫这张表。
# 统计各类错误的分布,用 awk 对错题索引表做快速聚合 awk -F, '{count[$2]++} END {for (err in count) print err, count[err]}' mistake_index.csv这个命令把错题索引表的第二列按错误类型统计频次。你会清楚地看到,范式分解题错了 7 次、SQL 嵌套查询错了 5 次、并发调度错了 3 次。哪块薄弱一目了然,下一轮复习直接按频次倒序去过知识点。
还有一个我踩过的坑想提醒你:答案文档里偶尔会有打印错误,比如关系代数表达式的下标写反、SQL 关键字大小写混用导致语法错误。这类问题对结果没影响,但会浪费你大量排查时间。遇到这种,用前面第 4 章的 SQLite 环境直接执行,执行报错就跳过该题,别跟它较劲。
回想起来,我当年最亏的就是把答案文档从头到尾抄了一遍,感觉自己是全班最努力的人,结果范式题换了个考法照样不会。之后改用“先做、再对、后归因”的办法,每一道错题都追到知识点层面,学习节奏才真正明朗起来。这个习惯我一直保留到今天,希望帮到你。
本文还有配套的精品资源,点击获取