2026/10/3 3:46:01

数据库实验从拆包到验收:SQL、ER图与避坑指南

数据库实验从拆包到验收:SQL、ER图与避坑指南 简介西安交大计算机数据库系统课程的lab作业合集主要面向该校计算机专业修读数据库课程的本科生用于课后实验练习与考前复习巩固。资源围绕数据库系统设计、SQL语言、数据库应用开发及高级特性四部分展开既涉及E-R模型和关系模型设计也包含DDL、DML、DQL、DCL等SQL操作以及Java/Python通过JDBC/ODBC调用数据库的实践内容。包内共37个文件以11个Python源码、12张PNG操作截图和9张JPG效果图片为主另有Markdown说明、依赖清单与环境配置等压缩包整体大小约5.86MB结构清晰便于按实验任务查找。文件中的代码模块覆盖建库建表、初始化数据、视图、存储过程、并发插入、冲突处理、备份恢复和性能对比等典型场景截图则记录了环境配置、终端执行和结果展示的关键步骤能帮助读者快速定位排错点。资源目前已有55人学习适合需要参照完整实验流程、或希望加深数据库实践理解的入门与进阶学习者。1. 拆开这个lab作业.zip之前先搞清楚里面装的是整套数据库实验说句实话看到一个叫“西安交大计算机数据库系统的lab作业.zip”的文件大多数人第一反应是双击解压然后对着解压报错对话框发呆。这个压缩包里装了什么决定了你后面两个小时的工作方式可能是SQL建表脚本和实验指导书也可能混着脏数据、伪加密标记甚至解压到一半就报CRC错误。处理器不能调到中间必须从第一层开始。这篇笔记按“拆包 → 环境 → SQL → ER图 → 避坑 → 验收”的顺序讲每一阶段都可复现适合临近提交节点的学生也适合帮学生验收作业的助教。2. 拆开lab作业.zip伪加密判断、密码移除与文件核对2.1 用十六进制编辑器判断是真加密还是伪加密“zip伪加密”不是玄学它在zip文件头里有一个明确的标志位。zip的本地文件头前四个字节固定是50 4B 03 04也就是ASCII的PK\x03\x04从偏移量6开始是通用位标志general purpose bit flag。这个标志的第0位置1表示文件被加密第3位置1表示有数据描述符。常见情况是标志位显示09 00低位是1说明“加密位”被置上了。可如果你去解压它却能解出来一半甚至某些工具能直接列出内容这就是典型的伪加密加密位被改动过但文件数据本身并没有真正加密。判断伪加密最直接的办法是用HxD这类十六进制编辑器打开压缩包看第二个文件头之前的字节。打开后能看到多个50 4B每个就是一个文件条目。把光标放在第一个本地文件头上跳到偏移量6读两个字节。如果该字节的最低位是1且文件列表里所有文件都提示要密码但压缩包来源又不像会设密码的样子就有八成的伪加密概率。import struct with open(lab作业.zip, rb) as f: data f.read(1024) # 本地文件头偏移量6处是通用位标志占2字节小端序 flag struct.unpack(H, data[6:8])[0] encrypted flag 0x0001 descriptor flag 0x0008 if encrypted: print(加密位已置位需要密码或按伪加密处理) else: print(未加密直接解压) if descriptor: print(注意启用数据描述符的zip可能由流式写入产生)这段代码只读取第一个文件头的标志位用来快速定位问题。需要注意一个zip里可能有多个文件条目如果第一个文件没加密后面某个文件加密了这个脚本就会误判所以严格做法是遍历所有本地文件头遇到任何一个加密位为1就单独标记。处理伪加密的办法也简单用十六进制编辑器把文件头偏移量6处的两个字节改成00 00或01 00保存后再解压。改之前先把原文件复制一份留底改坏了大不了重新下载这算是“后悔药”。如果你不想动十六进制也可以用7-Zip打开很多伪加密文件在7-Zip下直接就可以看到内容不必非要移除密码。2.2 真加密场景密码移除工具和暴力破解的适用边界如果确认不是伪加密而是真的设了密码处理思路要换一个。先想清楚这个密码是谁设置的实验指导书的附件一般是老师上传的不太可能主动加密如果是从网盘中转站下载的很可能是分享者加了密码防止爬虫。这种情况下与其花几小时去跑字典不如回到下载页面看说明密码往往就写在描述里比如“解压密码db2024”之类。只有连下载出处都找不到时才考虑密码移除工具。常见做法是用ZIP Password Recovery这类工具尝试但我要把话说明白对于强密码暴力破解的成功率极低而且这类工具大多只支持某种压缩算法跑出来的结果也不一定可靠。更稳的办法是回到文件来源重新获取原始压缩包或者干脆找同学要一份已经解压好的目录清单。别把时间耗在破解上数据库系统的lab作业重点在SQL和ER图不在档案学。2.3 解压后先做文件核对一份标准lab作业里应该有哪些内容解压成功只是第一步接下来要清点文件。我按接触过的数据库系统实验惯例列一个常见清单先核对一下文件类型典型文件名用途实验指导书实验一SQL查询.doc / 实验要求.pdf明确题目与评分点SQL脚本init.sql / student_course.sql建表、插入数据数据文件student.csv / course.csv外部数据导入报告模板实验报告.docx最终提交载体参考材料ER图示例.png / 关系代数答案.md提示解题套路清点时注意两点第一如果只有指导书没有数据文件说明数据要自己构造这时候按《数据库系统概论》里的学生课程库student/course/sc自己造几十行数据就能跑通第二如果压缩包里有一堆看不懂的冗余文件先不要删复制一份再整理因为提交时助教可能就按压缩包里的目录组织来验收。这里给一个命令行核对目录的命令# 在解压目录里列出所有文件按类型分组统计 find . -type f | awk -F. {print $NF} | sort | uniq -c | sort -rn这个命令会统计当前目录下各种后缀名文件的数量让你一眼看出这个lab作业.zip包含哪些类型资源。如果输出里.sql数量为0就要警惕数据是否齐全。3. 环境先跑通MySQL 8.0 zip版安装与SQL实验的完整操作3.1 MySQL 8.0 zip版在Windows 10上的安装路径与关键参数数据库系统的SQL实验一般以MySQL为主因为MySQL 8.0的zip免安装版在Windows上配置最灵活也最容易复现环境。在开始之前先去官网下载一个不带安装器的zip包解压到纯英文路径比如C:\mysql-8.0\。路径带中文会引发一系列编码问题这是一个前期就把坑埋下的地方。解压后数据目录默认在basedir下但建议显式指定。新建一个my.ini放在解压根目录# my.ini 最小可运行配置实际版本号以你下载的zip包为准 [mysqld] basedirC:/mysql-8.0 datadirC:/mysql-8.0/data port3306 character-set-serverutf8mb4 collation-serverutf8mb4_0900_ai_ci default-authentication-plugincaching_sha2_password max_connections200几个参数的用途basedir和datadir分别指定程序目录和数据目录port默认3306character-set-serverutf8mb4决定数据库默认字符集default-authentication-plugin是MySQL 8默认的密码认证插件后面连工具时要注意兼容性。接下来用管理员身份打开PowerShell执行初始化命令# 进入解压目录的bin文件夹执行初始化 cd C:\mysql-8.0\bin # 初始化数据目录使用不加密的root空密码 .\mysqld.exe --initialize-insecure --console # 注册为Windows服务 .\mysqld.exe --install MySQL80 --defaults-fileC:\mysql-8.0\my.ini # 启动服务 net start MySQL80 # 登录 mysql -u root -p--initialize-insecure的意思是初始化一个root空密码的数据目录方便第一次登录。很多人在这步翻车原因是之前已经初始化过data目录里残留了文件命令会报错。第一次执行前确认datadir指向的目录不存在或者里面是空的否则删除后重新初始化。服务安装成功后再用net start启动如果提示服务启动失败要回到第5章第5.2节去排查端口和数据目录问题。3.2 建库建表的关键写法主键、外键、CHECK约束的落地数据库系统的lab作业里前几题通常是给你一个“学生-课程”数据库要求你建立三张表学生表student、课程表course、选课表sc。这组表的建表SQL在《数据库系统概论》里就有但很多教材只给逻辑结构不给具体SQL需要自己落地。-- 创建数据库 CREATE DATABASE IF NOT EXISTS lab_db DEFAULT CHARACTER SET utf8mb4; USE lab_db; -- 学生表学号作为主键 CREATE TABLE student ( sno CHAR(10) PRIMARY KEY, sname VARCHAR(20) NOT NULL, ssex CHAR(2), sage INT, sdept VARCHAR(20), CONSTRAINT chk_ssex CHECK (ssex IN (男, 女)) ); -- 课程表 CREATE TABLE course ( cno CHAR(4) PRIMARY KEY, cname VARCHAR(40) NOT NULL, cpno CHAR(4), credit DECIMAL(3,1) ); -- 选课表复合主键加两个外键 CREATE TABLE sc ( sno CHAR(10), cno CHAR(4), grade DECIMAL(5,2), PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) );这段SQL里有几个细节值得较真。CHAR(10)用来存学号学号是定长编码用CHAR比VARCHAR更合适。CHECK约束在MySQL 8.0.16之后才真正生效如果你的版本较老这个约束可能只是“声明”但不强制评分时得注意。外键的REFERENCES语句把sc表和另外两张表关联起来保证插入的选课记录不能指向不存在的学生或课程这是实验报告里“参照完整性”的得分点。插入数据时尽量避免手写写一个init.sql脚本内容包含几千行INSERT……不过要小心如果在CREATE DATABASE前没加IF NOT EXISTS脚本第二次执行时会报错“数据库已存在”。所以我的习惯是在脚本顶部先加DROP DATABASE IF EXISTS lab_db; CREATE DATABASE lab_db;保证重跑不会污染上一遍数据。3.3 导入数据的三种方式source、重定向、LOAD DATA数据导入是SQL实验里卡住最多人的一步。我见过不少同学在Navicat里右键导入导入失败后搞不清楚原因。这里给出一条命令行路径全部在MySQL客户端里完成。第一种是直接用source命令在MySQL客户端内部执行USE lab_db; SOURCE C:/mysql-8.0/init.sql;注意Windows下source命令的路径分隔符是正斜杠反斜杠会被转义。第二种是从外部用重定向方式导入mysql -u root -p lab_db C:\mysql-8.0\init.sql这种方式适合在PowerShell里批量执行但前提是lab_db已经存在。第三种是把CSV数据导入表中这在处理实验数据文件时最常用LOAD DATA LOCAL INFILE C:/mysql-8.0/student.csv INTO TABLE student CHARACTER SET utf8mb4 FIELDS TERMINATED BY , OPTIONALLY ENCLOSED BY LINES TERMINATED BY \n IGNORE 1 ROWS;FIELDS TERMINATED BY ,指定逗号分隔OPTIONALLY ENCLOSED BY 处理CSV中被双引号包裹的字段IGNORE 1 ROWS跳过表头。如果导入时提示LOAD DATA LOCAL INFILE被禁用需要先在MySQL里执行一句SET GLOBAL local_infile 1;然后退出重进客户端。3.4 查询实验的评分视角这些细节最容易扣分SQL查询实验的评分不像填空那样机械助教看得最多的是三件事结果是否准确、是否用了题目标注的查询方式、语句是否规范。比如题目要求“用嵌套查询”你写一个连接查询虽然结果一样但会被判定不符合要求。这里列几条常见的扣分点第一题目要求查询“选修了课程号为C2的学生姓名”很多人在SELECT里忘了DISTINCT同一个学生选多门课就会重复出现第二统计类题目要求返回平均分但AVG()对NULL的处理可能和预期不符第三分组查询里WHERE和HAVING用反了WHERE过滤的是分组前的行HAVING过滤的是分组后的组这是数据库系统概论里的基础考点。-- 示例查询平均成绩大于85分的课程号及平均成绩 SELECT cno, AVG(grade) AS avg_grade FROM sc GROUP BY cno HAVING AVG(grade) 85;这条语句的GROUP BY把选课记录按课程分组HAVING在分组后过滤平均分大于85的组运行结果就是题目要求的课程列表。把这条和错误版本对比就能理解如果你把条件写成WHERE AVG(grade) 85MySQL会直接报错因为聚合函数不能出现在WHERE里。理解这个边界比记住十条语法更重要。4. 再写ER图与关系模式转换从例题到验收的完整路径4.1 用数据库系统概论ER图例题的思路确定实体、属性与联系画ER图是数据库系统lab作业里比重很大的一部分。很多同学面对一个需求描述就发懵不知道从哪里开始找实体。我的办法是先找名词再找动词名词大概率是实体或属性动词大概率是联系。比如“学生选修课程教师讲授课程”学生、课程、教师都是实体选修、讲授是联系成绩则是选修这个联系上的属性。这套方法可以用一个经典例题来演示“某学校有若干系每个系有若干班级和教师每个班级有若干学生每个学生选修若干门课程。”在这个描述里系、班级、教师、学生、课程都是实体班级属于系、教师属于系、学生属于班级、学生选修课程是联系。关键是你得区分实体和属性比如“系名”是系的属性还是独立实体取决于题目是否要求单独查询它。画图时要注意标注习惯实体用矩形属性用椭圆联系用菱形主键属性加下划线联系的类型要标注1:1、1:n还是m:n。西安交大计算机系这种lab作业里ER图通常要求用手绘软件完成但更重要的是你会不会把m:n联系拆成两个1:n。这一步经常被忽略却直接影响第4.2节的关系模式转换。4.2 从ER图到关系模式三个转换规则与两个必须避开的坑ER图转换成关系模式有三个核心规则实体转成关系表属性转成表的列主键由实体的标识属性决定1:n联系在n端表中加入1端表的主键作为外键m:n联系必须独立成一个关系表主键由两端实体主键组合而成。以“学生选修课程”为例转换结果是关系模式主键外键student(sno, sname, ssex, sage, sdept)sno无course(cno, cname, cpno, credit)cnocpno自引用sc(sno, cno, grade)(sno, cno)sno, cnosc表的主键是复合键这个复合键的引用完整性保证了选课记录不会“无中生有”。这里有一个常见思维盲区把“成绩grade”放在student表或course表里。成绩既不是学生固有属性也不是课程固有属性它是选课联系产生的结果只能放在sc表中。如果把它放错地方后面写SQL关联查询时会多出许多无用的连接。第二个坑是“冗余外键”。有些同学会把外键在两个方向都加上比如在course表里也加一个sno字段表示“被哪个学生选”结果就是数据冗余和更新异常。转换规则里已经说清楚了1:n时只在n端加外键m:n时用独立的中间表不需要在实体表里重复添加对方主键。4.3 关系代数表达式连接、选择、投影的书写顺序关系代数在数据库系统实验里不算大头但一定会有一两道题要写表达式。它的书写顺序和SQL语句的书写顺序是反的SQL把SELECT放最前面关系代数是先写连接再写选择再写投影。比如“查询选修了C2课程的学生姓名”关系代数写法是π sname(σ sc.cnoC2 (student ⋈ sc))这个表达式的执行顺序是从内到外的先做student和sc的自然连接然后选择cno等于C2的行最后投影出sname列。对应SQLSELECT DISTINCT sname FROM student JOIN sc USING (sno) WHERE cno C2;写关系代数时最容易犯的错是把π和σ的顺序颠倒先投影后选择结果就是选择的列已经被去掉了。另一个常见问题是漏掉连接条件直接写student × sc再选择的话助教一眼看出你没理解连接的本质可能会被扣分。这部分不必过度准备抓住连接→选择→投影的由内到外顺序即可。5. 避坑指南从zip到SQL最常见的五个血泪坑5.1 zip解压到一半报“CRC错误”或“数据错误”现象用右键“全部解压缩”到60%时突然弹出“数据错误”文件列表里只有部分文件能正常打开后面几个文件完全花掉。 原因压缩包在传输过程中损坏或者上传平台按文本模式处理了二进制文件。zip伪加密也会触发类似报错因为某些工具的识别和解压逻辑不一致。 解决先用7-Zip打开看能不能列出文件再用“工具→测试压缩包”定位到具体损坏的文件。如果只是个别文件坏了单独解压完好的部分损坏的部分找同学重新拷贝如果整个包都坏了用WinRAR的“修复压缩文件”功能生成一个fixed.zip它能重建一部分数据但不能保证全部恢复。实在不行就重新下载源zip包。5.2 SQL脚本执行失败报“Unknown database”或“Duplicate entry”现象source init.sql时报ERROR 1049 (42000): Unknown database lab_db或者再次执行同一脚本时报“Duplicate entry”。 原因第一种情况是脚本里没写CREATE DATABASE而你在客户端里也没先USE一个存在的库第二种情况是脚本可以重复执行但表里已有数据再次插入时主键冲突。 解决在脚本文件顶部统一加DROP DATABASE IF EXISTS lab_db; CREATE DATABASE lab_db; USE lab_db;这三句。这样一个脚本无论跑多少遍都是从头开始不会在已有数据上叠加。注意DROP DATABASE会清空整个库如果有需要保留的数据就把它拆成两个脚本分开跑。5.3 MySQL服务启动失败事件查看器里报端口占用或data目录错误现象执行net start MySQL80后提示“服务启动失败”或者服务列表里显示“正在启动”后立即停止。 原因两个最可能的点——3306端口被别的程序占用或者datadir目录下有残留文件导致初始化校验失败。 解决先用netstat -ano | findstr :3306看端口占用如果被占用要么把占用进程结束要么改my.ini中的端口号。再检查datadir目录内容如果之前初始化过把整个目录删掉重新执行mysqld --initialize-insecure --console。做完这两步再net start MySQL80基本能起来。5.4 导入CSV数据后中文全部变成问号现象用LOAD DATA导入CSV后SELECT出来中文列显示为???英文和数字正常。 原因客户端连接字符串没有指定字符集或CSV文件本身不是UTF-8编码。Windows默认的gbk编码在MySQL的utf8mb4库下导入后汉字直接映射失败。 解决在LOAD DATA语句里显式写CHARACTER SET utf8mb4并且在导入前用Notepad或VSCode把CSV另存为UTF-8无BOM格式。导入后用SELECT * FROM student LIMIT 5;抽查几条确认中文显示正常再继续后面的查询实验。5.5 画了ER图导出成PNG提交后放大模糊且缺少联系标注现象实验报告中嵌入了ER图图片放大后线条发虚而且图里菱形联系旁边没有标1:n或m:n。 原因导出分辨率太低或者画图时只画了实体框漏了联系类型标注。ER图的评分点是实体、属性、联系、键标注四个维度少一个都会被扣。 解决画图时先把联系的类型写在联系名称旁边比如“选修 m:n”导出时选SVG或PDF格式如果工具不支持矢量导出就选2倍以上缩放的高分辨率PNG不要直接截图。最后在报告里把ER图对应的关系模式表也放上助教看图的效率和准确率都会提升。6. 提交前验证与导出像助教一样用EXPLAIN和范式检查收尾6.1 SQL验证不是看结果而是看执行路径很多人跑完SQL看到结果跟题目预期差不多就交上去了但助教真正的评分重点不是那几行输出而是你写的SQL能不能在数据量变大之后依然高效。比如查询“没有选修任何课程的学生”写出WHERE not exists (select 1 from sc where sc.snostudent.sno)的人已经把自己和用not in的人区分开了。验证时对每一条带关联或子查询的语句在MySQL客户端执行EXPLAIN SELECT sname FROM student WHERE sno NOT IN (SELECT sno FROM sc);看输出里的type列和rows列如果type出现ALL说明全表扫描数据量到万级就会明显变慢如果出现eq_ref或ref说明走了索引。这不是炫技而是对照实验室“查询性能评估”这类题目的评分标准。计时也不难用SET profiling 1; SHOW PROFILES;可以看到每条查询的耗时提交报告时如果能附上这组耗时数据实验报告的质量会明显提升。6.2 范式验证与ER图修正在提交前把ER图转成的每个关系模式拿出来过一遍三范式看有没有部分函数依赖有没有传递函数依赖。检查方法很简单拿着表里所有非主属性逐个问“它是否依赖于主键的全部是否间接依赖于主键某个属性”。如果发现“教师姓名”依赖“教师编号”而“教师编号”又依赖“课程号”那就是传递依赖需要拆表。用这个思路把sc表和course表再检查一遍通常能避免提交后被退回修改的风险。6.3 提交格式与打包技巧最后打包提交的文件名最好按课程要求来比如“学号_姓名_实验一.zip”不要用原来的lab作业.zip直接交。打包时把data目录和临时my.ini排除只放SQL脚本、ER图、报告和README这样助教拿到就能直接跑。我自己习惯在提交前最后执行一遍mysql -u root -p lab_db init.sql确认脚本能从头跑到尾再把报告里的截图删掉换成最新一次查询的结果截图避免报告里的结果和图对不上。这算是我带实验课几年攒下来的血泪经验很多翻车不是代码问题而是提交物之间互相矛盾。希望帮到你。本文还有配套的精品资源点击获取