首页 / 资讯中心 / 文章详情

数据库入门:从SPJ案例理解关系模型与SQL本质

数据库入门:从SPJ案例理解关系模型与SQL本质 ★ FEATURED ARTICLE
简介本资源是《数据库系统概论第5版》王珊、萨师煊主编教材的配套课后习题参考答案面向高校计算机、软件工程、信息管理等专业本科生及数据库初学者用于辅助理解关系模型、SQL语言、关系代数等核心理论与实践难点。文件为单个Word文档.doc大小588KB内容覆盖第2章关系数据库与第3章SQL语言全部重点习题含关系模型三要素、完整性约束判定、等值连接与自然连接辨析、SPJ关系代数表达式推导、SQL建表与多表查询语句编写等典型题型的详细解答与解题思路。答案表述规范、步骤清晰部分题目还附有关键语法说明与易错点提示便于自学核对与考前复习。目前已有1723人学习下载是夯实数据库理论基础、提升SQL实战能力的实用参考资料。1. 这不是“背答案”的资料而是一份帮你把数据库从“黑匣子”变成“透明积木”的入门地图你刚翻开《数据库系统概论第5版》看到“关系代数”“参照完整性”“BCNF”这些词是不是像站在一扇厚重的金属门前——门上没把手、没锁孔、连缝都看不见翻两页就卡在“πSno(σJno‘J1’SPJ)”这串符号里心里发问这到底是在算数学题还是在解密码别急这份标着“王珊版答案”的.doc文件根本不是让你抄作业的参考书而是一张被前辈亲手画满批注、踩过坑、标好路标的实操地图。它用最朴素的问答体把抽象概念全锚定在“SPJ”这个四张表的小世界里谁供应零件、哪个工程用了什么颜色的货、为什么外码能为空、怎么用一条SELECT找出“没用天津红零件的工程号”……所有理论都长在具体数据、具体操作、具体错误上。它适合你——零基础但想真正搞懂“数据库到底在干啥”的人不是为考试突击刷题而是为以后写代码时不再对着FOREIGN KEY发呆、建表时不再乱加NULL、查数据时不再怀疑自己写的 SQL 是不是漏了括号。它不讲高深算法只解决一个最原始的问题当你说“我要存点数据”系统到底在背后做了哪些事又凭什么敢保证“不会丢、不会错、不会让不该看的人看见”这份答案就是带你一层层掀开那扇金属门看清里面齿轮怎么咬合的第一份说明书。2. 先搞懂一个事实数据库不是“电子表格”而是一套有脾气、讲规矩的协作系统很多人学数据库第一反应是“不就是 Excel 多几行”——这是最典型的认知偏差也是后续所有翻车的起点。这份答案文档从第二章第一个问题就开始掰开揉碎讲清这件事关系模型的三个组成部分就是数据库的“骨架、神经和血液”。它不是凭空造出来的而是为了解决真实协作中的混乱。我们用一个生活场景来类比假设你和三个同学一起做毕业设计要管项目进度、成员分工、提交的文档。如果用 Excel可能一人一个 sheet改完发群里最后合并时发现 A 同学删了 B 同学填的截止日期C 同学把“已完成”写成“已成”没人知道哪版是准的。而数据库就像给你们配了一个带自动校验的共享白板关系数据结构骨架它强制规定“进度表”必须有“任务名、负责人、状态、截止日”这四个格子且“负责人”这一格只能填你们四个人的名字不能填“隔壁班老王”这就是“实体完整性”关系操作集合神经你想查“所有状态为‘进行中’的任务”不用一行行翻只说SELECT * FROM 进度表 WHERE 状态 进行中系统自动扫全表、比对、返回结果——它不关心你怎么找只负责“精准送达”这就是“非过程化”关系完整性约束血液当有人想把“负责人”填成空系统立刻拦住“不行每个任务必须有负责人”或者有人想在“分工表”里填一个根本不存在的“任务名”系统也拒绝“这个任务名在‘进度表’里找不到不能认”——这些硬性规则就是数据库的“免疫力”防止垃圾数据污染整个系统。这份答案文档里反复出现的 SPJ 案例S供应商、P零件、J工程、SPJ供应关系就是这个协作系统的最小完整切片。你看它怎么用π投影和σ选择组合出“供应J1工程的供应商号”就是在看系统如何用最基础的“取列”和“筛行”两个动作搭出千变万化的查询逻辑。它不教你炫技只告诉你所有复杂功能都源于这五个基本运算并、差、笛卡尔积、投影、选择的排列组合。就像乐高再酷的机器人也由方块、圆柱、斜面这些基础件拼成。理解这一点你就不会被后面“除运算”“自然连接”吓退——它们只是基础件的新拼法不是新零件。2.1 关系代数不是数学考试而是描述“我要什么数据”的通用手语很多新手看到关系代数符号就头皮发麻觉得是数学题。其实完全相反它是比 SQL 更接近人话的“需求翻译器”。比如问题6的第一小问“求供应工程 J1 零件的供应商号码 SNO”。你脑子里想的是什么是不是“去 SPJ 表里把所有 JNO 是 ‘J1’ 的那些行找出来然后只留下 SNO 这一列”关系代数就是把这句话直译成符号πSno(σJno‘J1’SPJ)。σJno‘J1’SPJσsigma是“筛选”动作意思是“从 SPJ 表里挑出 JNO 列值等于 ‘J1’ 的所有行”πSno(...)πpi是“取列”动作意思是“把上面筛选出来的那些行只保留 SNO 这一列”。它不关心数据库内部怎么实现只清晰表达你的意图。这种“先想清楚我要什么再告诉系统”的思维正是数据库思维的核心。SQL 里的SELECT Sno FROM SPJ WHERE JnoJ1就是这句手语的“普通话版本”本质完全一样。文档里特意把关系代数和 SQL 并列给出比如第3章习题4就是在告诉你别被符号吓住它们都是同一种逻辑的不同表达。你练熟了σ和πSQL 的WHERE和SELECT就自然通透。2.2 “完整性约束”不是条文而是数据库给你配的“防错安全带”新手常问“为什么主键不能为 NULL”“为什么外码有时能空有时不能”这些问题的答案就藏在“完整性约束”这四个字里。它不是冷冰冰的教条而是数据库为你预设的“安全带”防止你无意识犯错。文档第2章第5题讲得特别透实体完整性比如“供应商表 S”的主键是SNO那每一行的SNO就像人的身份证号必须有、且唯一。如果允许为空系统就分不清“这个供应商还没填号”和“这个供应商根本不存在”——数据就乱了。所以规则是“主属性不能取空值”。参照完整性这是新手最容易懵的点。文档里说“外码可以为空但前提是它本身不是主属性”。我们用 SPJ 表解释SPJ(Sno, Pno, Jno, Qty)其中Sno是外码参照 S 表Pno是外码参照 P 表Jno是外码参照 J 表。如果某条记录的Jno是空的意味着“这个供应关系还没确定给哪个工程”这在业务上是合理的比如零件先备好工程还没立项。但Sno如果为空就等于“不知道是谁供应的”这在供应链里是不可接受的。所以规则是外码能为空仅当它在本表中不承担“唯一标识”作用时。这个“为什么”文档用“属性 F 本身不是主属性则可以取空值”一句话点破比死记硬背管用十倍。2.3 SQL 不是命令行而是你和数据库之间的“自然对话协议”很多人学 SQL上来就背CREATE TABLE语法结果写到JOIN就晕。这份答案文档的聪明之处在于它把 SQL 当作“对话”来教。第3章第1题总结的五大特点每一条都在解决一个沟通痛点综合统一你不用切换三种语言——建表DDL、查数据DML、管权限DCL全用 SQL高度非过程化你只说“我要所有上海供应商的零件”不用告诉系统“先查 S 表找上海的再查 SPJ 表匹配再关联 P 表取名字”它自动规划最优路径面向集合UPDATE P SET COLOR蓝 WHERE COLOR红这一句不是改一个零件而是把所有红色零件“批量染蓝”思维从“单个对象”升维到“整组数据”。文档里所有 SQL 示例都紧贴 SPJ 场景。比如第3章习题4的第(3)问“求供应工程 J1 零件为红色的供应商号码”SQL 写成SELECT SNO FROM SPJ,P WHERE JNOJ1 AND SPJ.PNOP.PNO AND COLOR红这里没有用JOIN关键字而是用经典的“逗号连接 WHERE 条件”写法。为什么因为这是最直白的“对话”“从 SPJ 表和 P 表里找数据”FROM SPJ,P“条件是SPJ 的 JNO 必须是 ‘J1’”JNOJ1“SPJ 的零件号必须等于 P 表的零件号”SPJ.PNOP.PNO“而且 P 表的颜色必须是 ‘红’”COLOR红。它像在跟朋友描述“你去两个名单里对照着找满足这三个条件的人把他们的编号给我。” 理解了这种“说人话”的逻辑INNER JOIN、LEFT JOIN就不再是魔法咒语而是更精确的“对照方式”。3. 第一步别碰代码先动手画一张属于你的“SPJ 四表关系图”所有数据库学习的崩溃点往往始于“脑内没地图”。你对着SELECT ... FROM SPJ,P WHERE ...发呆不是因为不懂语法而是根本没在脑子里构建出 S、P、J、SPJ 这四张表长什么样、它们之间怎么连。这份答案文档最大的价值就是它所有的理论、所有习题都牢牢钉在 SPJ 这个极简案例上。所以你入门的第一步不是打开电脑而是拿出一张纸亲手画出这四张表的结构和关系。这不是形式主义而是建立空间感的必经之路。我们按文档第3章习题4给出的建表语句来画3.1 用三分钟画出四张表的“身份证”和“连接线”先看每张表的“身份证”即字段和主/外键S 表供应商Sno(主键),Sname,Status,City—— 文档里建表语句CREATE TABLE S (Sno C(2) UNIQUE...)明确Sno是唯一标识P 表零件Pno(主键),Pname,Color,Weight——Pno是零件身份证J 表工程Jno(主键),Jname,City——Jno是工程身份证SPJ 表供应关系Sno,Pno,Jno,Qty—— 注意这里Sno、Pno、Jno都不是主键但文档明确指出它们是外码分别指向 S、P、J 表的主键。现在画“连接线”SPJ 的Sno→ 指向 S 表的Sno一根线SPJ 的Pno→ 指向 P 表的Pno第二根线SPJ 的Jno→ 指向 J 表的Jno第三根线。这张图就是你的数据库“神经系统”。以后任何查询比如“找上海供应商的红色零件”你第一反应就该是上海供应商 → 查 S 表City上海红色零件 → 查 P 表Color红它们怎么关联→ 必须经过 SPJ 表因为只有 SPJ 记录了“谁S供应了什么P给哪个工程J”。所以 SQL 必然是FROM S, P, SPJ WHERE S.SnoSPJ.Sno AND P.PnoSPJ.Pno AND S.City上海 AND P.Color红。画图的过程就是把抽象关系具象化的过程。很多高手写 SQL 前必画 ER 图原因就在此——脑子有图手才不抖。3.2 用一个真实查询验证你的“关系图”是否画对我们来实战验证。文档第3章习题4的第(4)问“求没有使用天津供应商生产的红色零件的工程号 JNO”。这个问题有点绕我们拆解“天津供应商” → S 表City天津“红色零件” → P 表Color红“天津供应商生产的红色零件” → 需要 S、P、SPJ 三表连接S.SnoSPJ.Sno AND P.PnoSPJ.Pno AND S.City天津 AND P.Color红“使用了这些零件的工程号” → 上面连接的结果里SPJ.Jno就是这些工程号“没有使用”的工程号 → 就是所有工程号SELECT Jno FROM J减去上面得到的工程号。文档给出的 SQL 是SELECT DISTINCT JNO FROM SPJ WHERE JNO NOT IN ( SELECT JNO FROM SPJ,P,S WHERE S.CITY天津 AND P.COLOR红 AND S.SNOSPJ.SNO AND P.PNOSPJ.PNO )现在对照你的关系图子查询里SPJ,P,S三表连接线是否都画对了S→SPJ via Sno, P→SPJ via Pno主查询SELECT JNO FROM SPJ为什么不是FROM J因为 SPJ 表里只存在“被使用过”的工程号J表里可能有未开工的工程但题目要求的是“没有使用”所以必须以 SPJ 为基准——这恰恰说明你的图里SPJ 是核心枢纽。如果你的图能清晰支撑这个逻辑恭喜你已经拿到了数据库世界的“导航仪”。3.3 避坑新手画关系图最容易踩的3个坑提示画图不是为了好看是为了让逻辑在脑子里“立起来”。以下坑我第一次学时全踩过血泪经验。坑1把外键当成主键导致关系错位现象在 SPJ 表里把Sno或Pno也标成主键加粗或打星画连接线时犹豫不决。原因混淆了“唯一标识”和“关联依据”。SPJ 的主键是(Sno, Pno, Jno)这个组合文档虽未明说但业务逻辑决定同一供应商对同一工程供应同一零件数量唯一单个Sno只是关联 S 表的“钥匙”不是 SPJ 自己的“身份证”。解决画图时只给 SPJ 表标一个组合主键框外键用虚线箭头单独指向 S/P/J 表标注“外码参照 S.Sno”等。坑2忽略“空值”的业务含义画出不可能的关系现象画图时给 SPJ 的Jno字段加了“NOT NULL”约束认为所有供应必须对应工程。原因脱离业务。文档第2章第5题明确说“外码可为空”比如零件已入库SPJ 记录存在但采购合同还没签Jno 未知此时Jno为空完全合理。强行加 NOT NULL会扼杀真实业务流。解决在图上给Jno字段旁手写小字“可为空表示工程未确定”。坑3连接时搞混“谁连谁”写出永远为空的查询现象写SELECT * FROM S, P WHERE S.Sno P.Pno运行结果为空百思不得其解。原因Sno 和 Pno 是不同维度的编码供应商号 vs 零件号直接比较毫无意义。连接必须通过“中间人”SPJ因为只有 SPJ 同时拥有这两个字段并定义了它们的关系。解决画图时S、P、J 三张表绝不直接连线所有连接线必须经过 SPJ 这个“十字路口”。这是铁律。4. 从“抄答案”到“真跑通”用 SQLite 亲手执行第一个 SPJ 查询光看答案、光画图不亲手敲一遍知识就浮在半空。现在我们把文档里的理论变成你电脑上真实跳动的数据。别怕没装数据库——SQLite 是一个文件就是一个数据库的轻量级引擎零配置5分钟搞定。我们用它来创建 SPJ 四张表并执行文档第3章习题4的第一个查询“求供应工程 J1 零件的供应商号码 SNO”。4.1 三步安装 SQLite比装微信还简单下载访问官网 sqlite.org/download.html搜索“sqlite-tools”下载对应你电脑系统的预编译二进制包Windows 下是sqlite-tools-win32-*.zipMac 下是sqlite-tools-osx-*.zip解压把 zip 包解压到任意文件夹比如D:\sqlite启动进入解压目录双击sqlite3.exeWindows或在终端输入./sqlite3Mac/Linux你会看到一个sqlite提示符——恭喜你的数据库已就绪注意SQLite 不需要“服务端”没有用户名密码一个.db文件就是完整的数据库。这对新手极其友好没有环境配置的玄学障碍。4.2 用文档里的建表语句亲手创建四张表我们严格按文档第3章习题4的CREATE TABLE语句来已根据现代 SQL 标准微调类型-- 创建 S 表供应商 CREATE TABLE S ( Sno TEXT PRIMARY KEY, Sname TEXT, Status INTEGER, City TEXT ); -- 创建 P 表零件 CREATE TABLE P ( Pno TEXT PRIMARY KEY, Pname TEXT, Color TEXT, Weight INTEGER ); -- 创建 J 表工程 CREATE TABLE J ( Jno TEXT PRIMARY KEY, Jname TEXT, City TEXT ); -- 创建 SPJ 表供应关系 CREATE TABLE SPJ ( Sno TEXT, Pno TEXT, Jno TEXT, Qty INTEGER, -- 添加外键约束SQLite 支持但需开启 FOREIGN KEY (Sno) REFERENCES S(Sno), FOREIGN KEY (Pno) REFERENCES P(Pno), FOREIGN KEY (Jno) REFERENCES J(Jno) );把以上 SQL 复制粘贴到sqlite提示符下每行后回车。如果看到Query executed successfully或无报错说明表创建成功。你可以用.tables命令查看当前有哪些表。4.3 插入测试数据让 SPJ 活起来文档里没给数据但我们可以用习题6的查询反推。比如要查“供应 J1 的供应商”至少得有一条JnoJ1的记录。我们插入几条典型数据-- 插入供应商 INSERT INTO S VALUES (S1, 精益公司, 20, 天津); INSERT INTO S VALUES (S2, 宏达厂, 10, 上海); -- 插入零件 INSERT INTO P VALUES (P1, 螺栓, 红, 10); INSERT INTO P VALUES (P2, 轴承, 蓝, 20); -- 插入工程 INSERT INTO J VALUES (J1, 一号厂房, 北京); INSERT INTO J VALUES (J2, 二号车间, 上海); -- 插入供应关系S1 供应 P1 给 J1S2 供应 P2 给 J2 INSERT INTO SPJ VALUES (S1, P1, J1, 100); INSERT INTO SPJ VALUES (S2, P2, J2, 200);每条INSERT执行后SQLite 会返回1 row inserted。现在你的 SPJ 数据库就活了4.4 执行第一个查询亲眼见证“πσ”如何变成屏幕上的结果回到文档第3章习题4的第(1)问SELECT DISTINCT SNO FROM SPJ WHERE JNOJ1。在sqlite提示符下输入SELECT DISTINCT SNO FROM SPJ WHERE JNOJ1;回车屏幕上会立刻显示S1就是这一行是你亲手从零搭建的数据库里挖出的第一颗数据钻石。它证明你理解了WHERE是“筛选”对应关系代数的σ你理解了SELECT DISTINCT是“取唯一列”对应π你理解了SPJ表里JNOJ1的行确实关联着SNOS1。这不是背出来的答案是你指挥数据库完成的一次真实协作。接下来你可以立刻尝试第(2)问SELECT DISTINCT SNO FROM SPJ WHERE JNOJ1 AND PNOP1结果依然是S1再试第(3)问需要连 P 表SELECT SNO FROM SPJ, P WHERE SPJ.JNOJ1 AND SPJ.PNOP.PNO AND P.Color红;结果还是S1。每一次成功都在加固你对“关系”二字的理解。5. 避坑新手执行 SQL 时最常遇到的5个“当场宕机”问题提示这些问题90% 的新手在第一次敲 SQL 时都会撞上。别慌它们不是你的错是 SQLite 在用它的方式和你打招呼。问题1输入 SQL 后按回车光标不动像卡住了原因SQLite 认为你还没输完因为 SQL 语句没以分号;结尾。它在等你补全。解决立刻输入;再回车。养成习惯每条 SQL 结尾必须加;。问题2报错no such table: SPJ原因要么表名拼错了比如写成spj小写SQLite 默认大小写敏感要么前面建表语句执行失败比如复制时多了空格要么你打开了新的sqlite3窗口之前的表没加载。解决输入.tables查看当前有哪些表确认建表语句无误确保所有操作在同一个sqlite3会话中进行。问题3SELECT * FROM SPJ返回空但明明插入了数据原因INSERT语句没加;结尾SQLite 没执行只是把它当成了多行输入。解决检查INSERT后是否有;执行.schema SPJ看表结构是否正确重新执行带分号的INSERT。问题4WHERE JNOJ1查不到但WHERE JNOj1能查到原因SQLite 默认区分大小写J1和j1是两个不同字符串。文档里所有例子都是大写你插入时也必须大写。解决统一用大写或在WHERE中用UPPER(JNO)J1强制转大写但性能略低。问题5外键约束不生效INSERT INTO SPJ VALUES (S999, P1, J1, 100)竟然成功了原因SQLite 默认不启用外键约束为兼容旧版本。这是最大陷阱解决在创建任何表之前先执行PRAGMA foreign_keys ON;。这是必须的第一步完整流程sqlite PRAGMA foreign_keys ON; sqlite CREATE TABLE S (...); sqlite CREATE TABLE SPJ (...);启用后再插S999就会报错FOREIGN KEY constraint failed这才是你想要的“安全带”。6. 下一步学什么从“会查”到“会设计”一条不绕弯的进阶路径当你能熟练地在 SQLite 里创建 SPJ 四表、插入数据、执行SELECT/INSERT/UPDATE/DELETE并理解每条语句背后的“关系”逻辑时恭喜你已经跨过了数据库学习最陡峭的坡。下一步不是去啃《数据库系统实现》这种大部头而是沿着一条清晰、务实、每一步都踩在真实需求上的路径把知识焊接到能力上。我的建议是用两周时间完成一个“微型图书管理系统”的闭环实践。它不大但五脏俱全能让你把文档里所有章节的知识点像拼图一样严丝合缝地嵌进去。6.1 用“需求驱动”代替“章节驱动”亲手设计你的第一个数据库别再从第一章开始读。打开一个空白文档写下你的真实需求“我要管理图书馆的书每本书有书名、作者、ISBN、出版年份、分类如‘计算机’‘文学’”“有多个管理员每人有工号、姓名、权限等级”“读者借书要记录借阅日期、应还日期、是否已还”“一本书可以被多人借一个人可以借多本书”。现在对照文档的章节把需求翻译成设计第2章关系模型→ 画出“图书”“管理员”“读者”“借阅记录”四张表标出主键ISBN、工号、读者ID、借阅ID和外键借阅记录表里的“图书ISBN”和“读者ID”第3章SQL→ 为每张表写CREATE TABLE为“查所有未还书”写SELECT为“添加新书”写INSERT第4章安全性→ 用GRANT SELECT ON 图书 TO 管理员控制权限SQLite 本身权限弱但语法要练第5章完整性→ 在“借阅记录”表加CHECK (应还日期 借阅日期)在“图书”表加UNIQUE(ISBN)第6章范式→ 当你发现“作者”字段里写了“张三,李四”就意识到该拆成“图书-作者”关联表这就是 1NF 到 2NF 的实战触发点。从那以后我每次设计新表都强制走一遍“SPJ 四表验证法”这张表的主键是什么能否唯一标识一行它的外键指向谁有没有对应的主键表它的字段会不会重复出现比如“出版社地址”在10本书里重复就该拆成“出版社”表它的业务规则能不能用CHECK或FOREIGN KEY写进建表语句这个习惯让我在后来参与某高校选课系统开发时避免了因“课程-教师”关系设计不当导致的排课冲突 bug。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站