简介这份答案文档对应数据库系统概论第5版·王珊版教材面向高校数据库课程学习者、考研复习者及自学人群。内容按章节编排覆盖关系模型三要素、关系完整性规则、关系代数五种基本运算以及SQL语言建表与嵌套查询等核心板块并针对SPJ数据库典型习题给出符号表达式、SQL语句与解题思路说明能够帮助读者快速核对作业、巩固关系数据库理论并提升查询书写能力。包体为1个独立doc文档整体大小588KB适配常见办公软件直接打开阅览便于打印或导入笔记工具。文档结构紧凑以文字解答为主适合边学边查也可作为章节复习提纲。资源目前已有1723人浏览学习属于数据库基础领域较常用的配套资料。对正在为王珊版教材习题或考试发愁的读者这份文档提供了从关系代数到SQL实践的对照参考可按章节直接用于查漏补缺。1. 数据库系统概论一本答案册背后的核心概念地图很多人第一次翻开《数据库系统概论》的答案册都会愣住第 2 章讲关系模型第 3 章讲 SQL第 6 章讲范式第 7 章讲设计流程——每个章节标题都认识连起来却不知道它们在解决什么问题。其实这门课就是整个数据库世界的“地基课”它要回答的始终是三个问题数据怎么组织才不乱、怎么查询才高效、怎么设计才不出错。搞懂这三个问题不管是应付考试、准备面试还是以后自己写点带存储的程序心里都会踏实很多。这本答案册的好处是把每个概念都拆成了“定义 例题 解答”照着读就能把零散的知识点串成一张网。接下来我就按这条主线把这几个核心概念一个个讲透。2. 关系模型把现实世界装进一张张表靠的是三张牌关系模型是数据库系统概论的第一个大重点。它的核心思想特别朴素把现实世界里的所有东西都装进一张张二维表里。学生是一张表课程是一张表选课记录又是一张表。但你有没有想过为什么偏偏是“表”这种形式能统治数据库几十年因为关系模型背后有三张牌在支撑少了任何一张这套体系都转不起来。2.1 三个组成部分结构、操作、约束一个都不能少关系模型的完整定义包含三部分关系数据结构、关系操作集合、关系完整性约束。通俗地说就是“长什么样”“能干什么”“有什么规矩”。关系数据结构就是指那些二维表本身。每张表有行、有列行叫元组列叫属性。比如一张“学生”表学号、姓名、系别就是属性每一行就是一个具体学生。这张表的骨架就是数据结构。光有骨架还不够你得能操作它——按条件筛选行、挑出需要的列、把两张表拼起来这些动作就是关系操作集合。关系完整性约束则是保证数据不出错的规矩它分两类实体完整性和参照完整性。实体完整性说白了就是“主键不能为空”——如果学号是主键那一行就不能没有学号否则你没法唯一确定是哪个人。参照完整性呢就是外键要么为空要么必须等于另一张表里真实存在的主键值。打个比方结构是房子的毛坯操作是你搬进去后的各种行为约束是物业规定“承重墙不能拆”。三者缺一不可。2.2 关系代数五种基本运算搭出所有查询关系操作的语言有三种关系代数、关系演算和 SQL。其中关系代数是理解后面所有查询的基础因为它是用一套数学符号来描述“怎么从表里取数据”的。关系代数一共有八种运算并、差、交、笛卡尔积、投影、选择、连接、除。但真正的基本运算只有五种并、差、笛卡尔积、投影、选择。其余三种都能由这五种推出。这就像乐高的五种基础积木有了并合并两表行、差减去某表行、笛卡尔积两表所有行两两组合、投影只挑某些列、选择只挑满足条件的行你就能搭出任何查询。比如经典的 SPJ 数据库问题——“求供应工程 J1 零件的供应商号码”写成关系代数就是π Sno (σ JnoJ1 (SPJ))π 是投影表示只取供应商号这一列σ 是选择表示筛选出工程号为 J1 的行。先选行再投影列两步就完成了查询。再复杂一点——“求没有使用天津供应商生产的红色零件的工程号”就需要先把供应商表 S、零件表 P、供应表 SPJ 做连接再用差运算把“用了红色天津零件的工程号”从全部工程号里减掉。整个过程像是拼积木每一步的输入输出都是一张新表。2.3 等值连接与自然连接一字之差结果截然不同连接运算是最容易翻车的地方尤其是等值连接和自然连接。很多人以为两者是一回事其实差别很关键。等值连接就是拿两张表中属性值相等的行拼在一起连接条件是“”。比如拿 S 表和 SPJ 表条件设为 S.SNO SPJ.SNO结果会生成一张包含两张表全部列的新表哪怕两列重名也照留不误。自然连接则是等值连接的特例它要求两个表中参与比较的属性必须是同名的属性组而且在结果中会自动把那个重复的同名列去掉。比如 S 表和 SPJ 表都有 SNO 列自然连接后SNO 只保留一列而不是两列。区别可以这样记等值连接是“条件相等就拼起来重复列我不管”自然连接是“相等且同名才拼拼完帮我删掉重复的那列”。实际做查询时如果你用的 SQL 里写的是 JOIN ... ON 两列相等那更像等值连接如果直接写 NATURAL JOIN那就是自然连接。这个区分在写作业和考试时几乎是必考的点。提示连接还有更细的分类比如内连接、外连接、左连接、右连接本质都是在“等值/自然”基础上决定哪些不匹配的行要不要保留。3. SQL 语言你只管说“要什么”不用管“怎么找”SQL 是数据库系统概论里比重最大的部分也是你毕业后真正会天天用的东西。但初学时最容易懵的不是语法而是它和普通编程语言的思维差异。普通编程语言你写的是“怎么做”——先循环、再判断、然后拼接SQL 你写的是“要什么”——给我满足这些条件的记录。这个差异就是 SQL 所谓的“高度非过程化”。3.1 非过程化点菜式操作后厨的事交给系统SQL 的五个特点里最核心的就是“高度非过程化”。用 SQL 操作数据你只需要提出“做什么”不需要指明“怎么做”。系统会自动决定怎么查最快、走哪个索引、用什么顺序访问表。打个比方你去餐厅点菜只需要说“来一份宫保鸡丁”至于后厨是先切肉还是先备料、用大火还是小火你完全不用管。SQL 就是那个点菜动作数据库管理系统就是后厨。而传统编程语言像是你钻进后厨每一步都得自己操刀。这个设计带来了一个直接好处同样的查询换了不同的数据库产品SQL 语句几乎不用改因为“怎么做”是由各家的系统各自优化的。这也是 SQL 能成为标准语言的原因——它把“用户意图”和“机器实现”彻底分开了。SQL 的另外几个特点也不是摆设。综合统一指它集数据定义DDL、数据操纵DML、数据控制DCL于一体建表、查询、授权都能用一套语法完成。面向集合指它的操作对象和结果都是元组的集合一次能插入或删除多行。两种使用方式指 SQL 既能作为独立语言在终端交互使用也能嵌入到高级语言里配合程序使用。最后“语言简捷易学易用”你不是已经感受到了吗3.2 建表与查询一段 SQL 读懂核心语法SQL 语法的骨架很简单就四类CREATE 建表、SELECT 查询、UPDATE 更新、DELETE 删除。我们拿答案册里的 SPJ 数据库举例。先建供应商表CREATE TABLE S ( Sno CHAR(2) UNIQUE, Sname CHAR(6), Status CHAR(2), City CHAR(4) );这个语句的意思很清楚建一张叫 S 的表有四列Sno 是字符型且不能重复UNIQUE其他列也各自限定了长度。建表时需要想清楚两件事每列的数据类型和取值范围以及哪些列有唯一性要求。建完表就能查了。比如“找出所有供应商的姓名和所在城市”就两行SELECT Sname, City FROM S;再比如“求供应工程 J1 零件 P1 的供应商号码”要的是同时满足两个条件的记录SELECT DISTINCT SNO FROM SPJ WHERE JNOJ1 AND PNOP1;这里的 DISTINCT 是去重因为同一个供应商可能给 J1 供过好几次不同批次的零件只要号码出现一次就够了。WHERE 后面跟的是筛选条件AND 表示必须同时成立。写的时候注意字段名别写错字符串用单引号这就是初学者最容易踩的坑。3.3 视图一扇不会存数据的窗户视图是 SQL 里特别容易理解错的概念。很多人以为视图就是一张“临时表”其实它的本质更像是一扇窗户——你透过窗户能看到院子里的花但窗户本身不种花。定义上说视图是从一个或几个基本表导出的表本身不独立存储在数据库中数据库里只存放视图的定义不存放视图对应的数据。这些数据仍然存放在原来的基本表里。所以视图也叫虚表。用户在概念上可以像用基本表一样使用视图甚至可以在视图上再定义视图。视图有什么好处答案册总结了四点简化用户操作让用户从多角度看待同一数据对重构数据库提供逻辑独立性以及对机密数据提供安全保护。最后这点特别有用——你不想让某个用户看到工资列就可以建一个不含工资列的视图把视图的查询权限给他而不是直接给整张表的权限。但视图也有个硬伤不是所有视图都能更新。基本表的行列子集视图一般可以更新但如果视图的属性来自集合函数比如 MAX、AVG、表达式那它肯定不能更新。道理也简单视图本身不存数据对视图的更新必须转换成对基本表的更新。如果这种转换不能“唯一有意义”地完成系统就只能拒绝更新。比如一个视图展示“每个部门的最高工资”你没法把这个视图里的某一行的“最高工资”改掉而不引起歧义——改哪个员工的工资系统不知道所以不许改。4. 安全性与完整性数据防贼和防错的易混区分数据库系统概论里有两个概念经常被搞混安全性和完整性。它们听起来都在“保护数据”但防的东西完全不同。安全性防的是“人”——防止非法用户偷偷访问、篡改数据完整性防的是“数据本身”——防止不符合语义的坏数据混进来。打个比方安全性是给数据装门锁不让坏人进来完整性是给数据配质检员就算人进来了录入的数据不对也得拦下来。4.1 安全性控制五道防线层层设卡数据库的安全性控制常见方法有五种用户标识和鉴别、存取控制、视图机制、审计、数据加密。这五道防线是层层递进的。用户标识和鉴别是第一道门——你告诉系统你是谁系统核对用户名和口令通过才放行。这道门只解决“你是谁”的问题不解决“你能干什么”。存取控制是第二道门——你进来了但系统要检查你有没有权限读这张表、改这条记录。比如你只是普通员工系统就不会让你执行 DELETE 语句。视图机制是第三道门——就算你有查询权限也只能查到被允许看到的那部分数据。为了不让某个用户看见别人的工资给他一个不含工资列的视图就行。审计是第四道门——它不拦人而是把一切操作记录下来记下“谁在什么时间对哪条数据做了什么”。如果数据出了事DBA 能靠审计日志回放现场找出肇事者。数据加密是最后一道防线——就算有人把硬盘偷走了拿到的是加密后的乱码没有密钥也还原不出内容。4.2 自主存取控制 DAC 与强制存取控制 MAC 的区别这两者是最容易混淆的一对。答案册里的解释很长用一句话总结就是自主存取控制是“我自己说了算”强制存取控制是“系统说了算”。自主存取控制DAC的逻辑是数据的所有者有权决定谁能访问自己的数据。比如你是表的创建者你可以用 GRANT 语句把查询权限授给同事还能用 WITH GRANT OPTION 让他也获得转授权的权力不想给了就用 REVOKE 收回。它灵活但有个弱点——权限可以在用户间传递容易失控。强制存取控制MAC完全不同。每个数据对象都被系统强制标上一个密级绝密、机密、可信、公开每个用户也被强制授予一个许可证级别。用户只能访问级别不高于自己许可证的数据。这个过程不依赖任何人的主观意愿系统说了算。两者的对比可以看这张表对比维度自主存取控制 DAC强制存取控制 MAC决策者数据所有者系统强制规则核心语句GRANT / REVOKE密级标签 许可证灵活性高权限可转授低规则硬性安全级别C2 级B1 级防违规传播较弱强实际应用中商用数据库一般用 DAC 为主涉密系统才需要 MAC。GRANT 语句长什么样看这个例子GRANT SELECT, INSERT ON Student TO 王平 WITH GRANT OPTION;意思是把 Student 表的查询和插入权限授给用户王平并且允许他再转授给别人。收回权限就写REVOKE INSERT ON Student FROM 王平 CASCADE;CASCADE 表示级联收回——如果王平把权限转授给了别人那些人的权限也一并收回。4.3 完整性约束的六种分类与违约处理数据库的完整性靠约束条件来保证这些约束条件可以分成六类静态列级、静态元组、静态关系、动态列级、动态元组、动态关系。初学者常在这里迷失其实背后的分类逻辑特别简单先看“静态还是动态”再看“约束对象是谁”。静态是针对结构不变的场景动态是针对修改变动的场景。列级约束管单个列的值元组约束管一行内各列之间的关系关系约束管多行或多表之间的关系。举个例子“年龄不能超过 60 岁”是静态列级约束“工资不低于部门平均工资的 60%”是元组级或关系级约束“更新工资后旧值和新值之间的差距不能超过 20%”就是动态列级约束。违反约束时系统的处理方式也值得注意。答案册明确说违反实体完整性和用户定义完整性系统一般直接拒绝执行但违反参照完整性不一定会被拒绝而是要根据应用语义做附加操作。比如删除一个供应商如果他在 SPJ 表里有供应记录系统可能采取三种做法之一级联删除把他的供应记录一起删掉、受限删除不允许删、置空值删除把他相关记录里的供应商号置空。到底用哪种取决于业务上“失去供应商后供应记录还有没有保留价值”。5. 函数依赖与范式从 1NF 到 BCNF表该怎么拆才算好数据库设计中最让人摸不着头脑的就是范式了。1NF、2NF、3NF、BCNF背定义时觉得每个字都认识做题时却不知道拿哪些属性去“套”。要理解范式关键要先把函数依赖搞明白。函数依赖不复杂它就是描述“一个值能不能唯一确定另一个值”。5.1 函数依赖一张身份证定终身定义里说如果两个元组在 X 上的值相等在 Y 上的值也一定相等就称 Y 函数依赖于 X记作 X→Y。通俗地说X 能唯一确定 Y。比如学号能确定姓名因为同一个学号只会对应一个人所以 Sno→Sname。但姓名不能确定学号因为可能重名。函数依赖有三种特殊形态特别容易考完全函数依赖、部分函数依赖、传递函数依赖。完全函数依赖是指 X→Y但 X 的任何真子集都不能确定 Y。比如 (Sno, Pno)→Qty只有同时知道学号和课程号才能确定成绩单独任何一个都确定不了。部分函数依赖是指 X→Y但 X 的某个真子集也能确定 Y。比如 (Sno, Class)→Dept其实光靠 Sno 就能确定 Dept那么 Y 对 X 就是部分函数依赖。传递函数依赖是指 X→YY→Z且 Y 不能确定 X。比如 Sno→ClassClass→Dept那么 Sno→Dept 就是传递依赖。在答案册的“学生”关系模式里Sno→Class→Dept→Rno宿舍区所以学号和宿舍区之间存在传递依赖。这会造成什么问题如果某个系换了宿舍区你就得把所有该系学生的宿舍区逐一更新漏改一条数据就出错了。这就是冗余带来的更新异常。5.2 范式递进每爬一层消除一类“毛病”范式的本质就是对表的拆分程度做的等级划分。每升一级就消灭一类隐患。第一范式1NF要求表里的每个分量都是不可再分的原子值。什么意思就是不能在一格里存“北京海淀”这种带逗号的两个信息。这是底线几乎所有关系表都天然满足。第二范式2NF要求在 1NF 基础上消除非主属性对码的部分函数依赖。换句话说如果你的码是复合的比如学号课程号那所有非主属性都得完整地依赖整个码不能只依赖其中一半。比如一张表里码是 (学号, 课程号)但“姓名”只依赖学号它跟课程号没关系这就是部分依赖这张表就不满足 2NF。解决办法是把表拆开学生表和选课表分开存。第三范式3NF要求在 2NF 基础上消除传递依赖。也就是说非主属性不能“绕路”依赖主码。比如学生表里学号确定系名系名确定宿舍区那么宿舍区就和学号之间隔着系名这就是传递依赖。拆法是把“系”单独拎出来成一张表学生表里只留系编号。BCNF 是 3NF 的加强版。3NF 允许“码”和“非主属性”之间存在一些不那么完美的依赖关系BCNF 干脆规定任何决定因素都必须包含码。也就是说只要某个属性能决定其他属性它自身就得是码的一部分。这是判断一张表是否“纯洁”的高标准。5.3 范式是拆表的尺子不是越拆越好那是不是范式等级越高越好不一定。答案册里有一个经典的结论任何一个二目关系只有两个属性的关系都一定是 3NF也一定是 BCNF。因为只有两个属性时一个属性要么单独是码要么两个一起是码不存在传递依赖也不存在非码属性决定另一个属性的情况。所以做题时遇到只有两个属性的关系可以直接判 BCNF。但现实中不建议把表无条件拆到最高范式。范式解决的是“更新时不出错”但代价是查询时要多连接好几张表性能会下降。一个常用的做法是频繁更新的事务型场景尽量做到 3NF 甚至 BCNF报表类、分析类的只读场景反而可以刻意保留一些冗余把表“退”到 2NF用空间换查询速度。拆表没有绝对标准只有针对业务场景的选择。6. 数据库设计六阶段从 E-R 图到建表拆到什么程度才算够数据库系统概论的最后一章把整个设计过程总结成六个阶段需求分析、概念结构设计、逻辑结构设计、数据库物理设计、数据库实施、数据库运行和维护。这六个阶段是一个完整项目的全生命周期。需求分析搞清楚用户到底要什么数据、要做什么处理。概念结构设计把需求抽象成一个独立于具体数据库产品的概念模型——最常见的就是 E-R 图用实体、属性和联系描述现实世界。逻辑结构设计把 E-R 图转换成某个具体数据库支持的关系模型也就是实际建表。物理设计考虑存储结构和索引。实施就是把设计变成真实运行的数据库调试程序导入数据。运行维护则是在长期使用中不断评估和调整。概念结构设计阶段有一个策略选择问题自顶向下先定全局框架再细化、自底向上先做局部再集成、逐步扩张从核心往外扩、混合策略两者结合。做小项目时用自底向上比较顺手做大型系统时通常得混合着来。范式在这里的作用是“逻辑结构设计阶段的优化工具”——表结构初步确定后用范式去检查每个关系模式如果有部分依赖或传递依赖就考虑拆表。但拆到什么程度要看查询需求。我记得有次给某个跨平台系统的数据模块设计表结构一上来把所有表都拆到 BCNF结果报表查询要 join 七八张表慢到客户端直接超时。后来才发现报表场景其实更适合保留冗余字段事务表才需要严格范式化。从那以后我每次设计表都会先问自己一个问题这批数据是“经常被更新”还是“经常被读取”前者的表老老实实上 3NF 以上后者的表大胆保留冗余。这门课的内容一环扣一环——关系模型给你表和运算的框架SQL 让你高效取数完整性守质量底线范式帮你把表拆得清晰、设计出不易出错的结构。希望这篇讲透核心概念的梳理能帮到你再去翻那本答案册时每一章的标题应该都不再陌生了。本文还有配套的精品资源点击获取