数据库课程设计工程包解析:从建库SQL到Python演示代码的完整跑通路径 简介南京航空航天大学人工智能专业2024年《数据库原理》课程设计项目是一份完整的课程实践资源包压缩包内共含6个文件包括2个SQL脚本建库脚本与运行脚本、1个Python程序、1份PDF上机实验报告、1个README说明文件及1个txt文本文档整体仅1.92MB便于下载与浏览。这份资源围绕数据库原理课程的核心任务展开既涉及数据库表结构定义、数据增删改查、索引与触发器又通过Python脚本演示了数据库编程接口的调用覆盖SQL语言、数据模型、关系规范化、查询优化、事务管理等重要知识点。对于正在学习数据库原理或需要完成类似课程设计的人工智能专业学生可以直观展示从需求分析、概念设计、逻辑设计、物理实现到测试维护的完整流程帮助理清设计脉络借鉴南航的教学要求与实现方式。实验报告详细记录了上机实践过程与运行结果配合可直接运行的脚本便于读者对照验证或二次开发。目前已有212人学习是理解数据库课程设计规范、快速搭建实验环境的实用参考。1. 数据库课程设计完整工程包从建库脚本到演示代码先跑通再谈加分某高校人工智能专业《数据库原理》课程设计交上去的是这样一个压缩包SQL 脚本、Python 主程序、依赖清单、实验报告 PDF外加一份 README。很多同学拿到这类工程包的第一反应是打开 README 找运行步骤结果发现文档只写了「环境要求」四个字。这套资源的价值不在于代码量有多大而在于它把一门数据库课设要交的东西全部按工程方式组织好了——从 setup.sql 建库建表到 run.sql 演示查询再到 main.py 把 SQL 串成业务逻辑。适合两类人一是准备做数据库课设但没想清楚整体结构的学生二是想复现一套完整「建库—写代码—出报告」流程的初学者。先说明一点这套工程最常见的载体是学生选课成绩管理这一类小型系统下文全部按这个场景展开。2. 先看懂工程里的 SQL 文件setup.sql、run.sql 的分工与执行顺序2.1 setup.sql 承担了什么建表、约束与初始数据大多数课设包里的 setup.sql 负责的是数据库的「地基」创建数据库、建立数据表、定义主键外键、写入初始数据。以学生选课成绩管理系统为例你会在 setup.sql 里看到这三类核心表的定义逻辑CREATE DATABASE IF NOT EXISTS db_course DEFAULT CHARACTER SET utf8mb4; USE db_course; CREATE TABLE student ( sno CHAR(10) PRIMARY KEY, sname VARCHAR(20) NOT NULL, ssex CHAR(2) DEFAULT 男, sage TINYINT ); CREATE TABLE course ( cno CHAR(6) PRIMARY KEY, cname VARCHAR(40) NOT NULL, ccredit DECIMAL(3,1) ); CREATE TABLE score ( sno CHAR(10), cno CHAR(6), grade DECIMAL(5,2), PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) );这段代码的逻辑很直白student 表用学号做主键course 表用课程号做主键score 表是典型的选课关系表用 (sno, cno) 联合主键同时把 sno 和 cno 设为外键。参数上有两个细节值得注意。第一个是 DEFAULT CHARACTER SET utf8mb4如果建库时不指定字符集MySQL 会走默认配置插入中文姓名时大概率会变成一串问号。第二个是 sage 用 TINYINT选课成绩系统的学生年龄范围不会超过 127用 INT 纯属浪费空间——课程设计评审里对「数据类型选取得当」是有印象分的。运行 setup.sql 之后数据库里应该能看到完整的表结构和初始数据。建议跑完立刻用 SHOW TABLES 确认表数量再用 SELECT COUNT(*) 确认每张表的行数这是判断脚本有没有半途报错的最快方式。2.2 run.sql 是演示脚本查询、视图与事务的编排run.sql 在课设包里的角色是「给评审老师看的演示稿」。它不会像 setup.sql 那样做大量 DDL而是把课程设计报告里写的那些核心查询、视图、事务操作按顺序排好保证老师或助教执行一遍就能看到所有加分项。-- 查询每门课程的选课人数和平均分 SELECT c.cname, COUNT(s.sno) AS stu_count, AVG(sc.grade) AS avg_grade FROM course c LEFT JOIN score sc ON c.cno sc.cno LEFT JOIN student s ON sc.sno s.sno GROUP BY c.cno, c.cname ORDER BY avg_grade DESC; -- 创建视图显示成绩低于60分的学生信息 CREATE OR REPLACE VIEW v_failed AS SELECT s.sno, s.sname, c.cname, sc.grade FROM student s JOIN score sc ON s.sno sc.sno JOIN course c ON sc.cno c.cno WHERE sc.grade 60;这里的核心是 JOIN 的方向。LEFT JOIN 配合 GROUP BY 可以查出「还没人选修的课程」——如果某门课的选课人数是 0用 INNER JOIN 会把这门课整行过滤掉严重时会导致排序结果和报告对不上。CREATE OR REPLACE VIEW 后面通常还会跟几条 SELECT 验证视图数据如果你拿到的 run.sql 只有视图定义没有验证语句自己补上两行 SELECT * FROM v_failed演示效果会完整很多。除了查询和视图run.sql 里通常还会有一段事务操作常见的形态是模拟选课扣减容量开启事务、插入 score 记录、检查是否冲突、正常则提交否则回滚。执行它的时候重点关注 COMMIT 和 ROLLBACK 的分支是否都在缺了任何一条事务演示都是不完整的。2.3 拿到脚本后第一步按依赖顺序在 MySQL 里跑通一个最常见的翻车点是把 run.sql 在 setup.sql 之前执行或者在 setup.sql 还没跑完时就急着看后面的结果。正确的执行顺序是这样的mysql -u root -p setup.sql mysql -u root -p run.sql从这里能看出两个工程细节。第一setup.sql 里 CREATE DATABASE 和 CREATE TABLE 有严格的先后依赖少了前者后者必然报错第二run.sql 里的查询依赖 setup.sql 写入的数据必须先有数据才能出结果。如果你用的是图形化客户端就按文件名逐个打开执行别用「全部运行」一把梭否则报错信息会淹没在同一条执行日志里定位问题得翻半天。「先建库、再演示、最后跑代码」是这套工程包唯一的正确顺序。执行完后做一个快速自查SHOW TABLES 能看到三张以上的业务表SELECT 能返回非空结果集视图能正常查询。走到这一步数据库侧的工作就已经通了。3. main.py 不是玩具代码连接管理、参数化查询与业务分层3.1 数据访问层怎么写连接对象、游标与关闭逻辑main.py 是这个工程包里 Python 与 MySQL 之间的桥。课设级别的代码连接部分常见用的是 pymysql连接参数大概率写在一个函数里方便其他地方反复调用。import pymysql def get_conn(): conn pymysql.connect( host127.0.0.1, port3306, userroot, passwordyour_password, databasedb_course, charsetutf8mb4, cursorclasspymysql.cursors.DictCursor ) return conn这段代码的关键参数要逐个说清楚。host 和 port 默认是本机 3306如果连接的是 Docker 容器里的 MySQLhost 要改成容器映射出来的地址。charset 必须和 setup.sql 里的 utf8mb4 保持一致否则 Python 写入中文时会在编码转换上报错。cursorclass 用 DictCursor 会让查询结果以字典形式返回输出时可以直接用 row[sname]比默认的元组取值友好得多课设报告里的打印代码也因此会短一截。任何连接对象都必须有对应的关闭动作。很多初写的 main.py 只开不关程序跑完连接池耗尽第二次运行就报 Too many connections。常见做法是每次用完后在 finally 块里同时关闭游标和连接写成结构化的上下文管理器形式更稳。3.2 业务逻辑层到控制台菜单增删改查的完整闭环课设的 main.py 通常长这样一个 while 循环打印菜单用户输入数字选择功能每个分支调用一个函数函数内部执行 SQL 并打印结果。以学生信息管理为例插入和查询的核心逻辑是这样组织的def add_student(conn): sno input(请输入学号: ) sname input(请输入姓名: ) ssex input(请输入性别: ) sage int(input(请输入年龄: )) with conn.cursor() as cur: cur.execute( INSERT INTO student (sno, sname, ssex, sage) VALUES (%s, %s, %s, %s), (sno, sname, ssex, sage) ) conn.commit() print(学生信息添加成功) def query_student(conn): keyword input(请输入姓名关键字: ) with conn.cursor() as cur: cur.execute( SELECT sno, sname, ssex, sage FROM student WHERE sname LIKE %s, (f%{keyword}%,) ) rows cur.fetchall() for r in rows: print(r[sno], r[sname], r[ssex], r[sage])这两段代码体现了课设代码和玩具代码的分水岭。第一参数全部用 %s 占位符传参杜绝了直接字符串拼接 SQL 的写法这一点在答辩时经常被问到回答「防止 SQL 注入」比「别人都这么写」体面得多。第二INSERT 之后在连接对象上调 conn.commit()pymysql 默认 autocommit 是 False不写 commit 数据不会真正落库重启程序后数据消失这是最常见的低级事故。第三LIKE 查询的模糊匹配关键字也要通过参数传入百分号拼在参数内部SQL 语句本身保持干净。菜单部分通常是 while True if/elif 的结构每个分支调用一个函数。需要注意的是退出分支必须 break 之前关闭连接对象否则 CtrlC 强制退出后连接会滞留在数据库侧。3.3 从课设代码到可评审代码注释、异常与输出格式评审老师打开 main.py 时不会一行行数代码量但会看三个地方有没有处理异常、有没有写清楚注释、控制台输出是不是人能看明白的格式。这三个点都不难做但很多工程包恰恰缺在这里。异常处理最值得补的是连接失败和 SQL 执行失败两个场景try: conn get_conn() except pymysql.err.OperationalError as e: print(数据库连接失败请检查 MySQL 服务是否启动) print(f错误码: {e.args[0]}错误信息: {e.args[1]}) exit(1)e.args 里装的是 MySQL 报错的错误码和描述信息比如 1045 是密码错误2002 是端口不通或服务没起。把这两个参数打出来排查问题的时候比只看「连接失败」四个字高效太多。注释方面不需要每行都写但每个函数上方的三行 docstring 是值得留的写清楚函数做什么、入参是什么、返回什么报告里贴代码的时候也方便直接裁剪。输出格式上查询结果打印前先打一行字段名分隔线比直接堆元组好看得多这一条能从观感上直接把代码档次拉高一分。4. 运行前先治理环境requirements.txt、Python 版本与依赖安装顺序4.1 requirements.txt 里常见依赖与版本陷阱这个工程包里的 requirements.txt 篇幅不长但内容直接决定 main.py 能不能跑起来。以 pymysql 为核心的课设依赖清单常见长这样pymysql1.0.2 cryptography3.4.8 pandas1.3.0三个依赖各有用处。pymysql 是数据库驱动负责 Python 与 MySQL 之间的通信cryptography 在 MySQL 8.0 以上版本几乎必须装因为新版 MySQL 默认的 caching_sha2_password 认证插件需要它来做加密握手不装就会在连接时直接报认证失败pandas 不是必需品但报告里如果涉及成绩分布统计、平均分对比这类数据分析图表main.py 里大概率会用它辅助处理查询结果。版本陷阱集中在 pymysql 上。1.0.2 以上版本对 Python 3.8 以下不再提供支持如果你用的是 Python 3.6 的老环境pip 安装时会直接报找不到匹配版本。这时候两个选择升级 Python 到 3.8或者把 pymysql 版本降到 0.10.1。我的建议是前者降版本虽然能装上但老版本对 utf8mb4 和 DictCursor 的支持都不如新版稳。4.2 安装依赖与初始化数据库的一体化流程复现这套工程包的完整顺序应该是先建虚拟环境再装依赖然后初始化数据库最后跑 main.py。命令行下就是这么一串python -m venv venv source venv/bin/activate # Windows 下用 venv\Scripts\activate pip install -r requirements.txt mysql -u root -p setup.sql mysql -u root -p run.sql python main.py这里的顺序有一个容易忽略的细节先装依赖再导 SQL。因为 main.py 里的连接参数尤其是密码可能要改而改完密码后的第一件事就是重新验证连接如果 SQL 侧的表还没建好连接测试会卡在「数据库不存在」这个错误上。反过来如果先建库再装依赖万一依赖安装失败数据库已经建了一半排错时还得顾两边状态太乱。虚拟环境这一步在任何机器上都值得做。直接用系统 Python 装 pymysql 也不是不能跑但机器上多个项目共存时版本冲突迟早出问题。venv 把依赖隔离在当前目录删掉重来也就一条 rm -rf venv 的事。4.3 README 没写全时怎么从文件倒推运行逻辑很多课设包的 README 只有寥寥几句环境要求拿到手根本没法直接照做。这时候看文件依赖关系比看文档更可靠判断顺序只有两条。第一从文件命名判断执行顺序setup 开头的永远是最先执行的run 开头的紧随其后main 结尾的 Python 文件最后运行。第二从 import 语句判断依赖层次打开 main.py 看顶部 import 了哪些库再去 requirements.txt 里核对是否存在缺谁装谁不必一次性全装完。文件包里那份实验报告 PDF 也是重要的信息来源。报告里的「系统运行截图」「数据库设计说明」章节几乎必然包含表结构、SQL 和运行结果技术上先参考报告再回看代码比对着空代码盲猜快得多。这套流程走下来即使 README 只写了三行工程包也能在十分钟内跑通。5. 避坑把这套工程复现三遍之后总结出的五个问题5.1 现象setup.sql 执行时报错错误码 1064提示 syntax error原因文件编码不是 UTF-8。Windows 下用记事本保存的 SQL 文件经常是 GBK 编码MySQL 客户端按 utf8mb4 解析时中文字符串的字节序列触发语法解析错误。解决用 VS Code 或任意编辑器打开 setup.sql右下角查看编码格式另存为 UTF-8或者在 mysql 命令行执行前先执行 SET NAMES utf8mb4。我一般直接把所有 SQL 文件统一转成 UTF-8 再入库一劳永逸。5.2 现象setup.sql 单独执行成功放到工程包里再执行就报外键约束错误错误码 1215原因表之间的创建顺序不对。score 表引用了 student 和 course如果先执行 score 的建表语句而被引用的表还不存在外键约束自然建立失败。解决打开 setup.sql 检查 CREATE TABLE 顺序先建被引用的表再建引用表。如果脚本里顺序已经乱掉把外键约束从建表语句里拆出来单独放到文末用 ALTER TABLE 补上。更简单的办法是把三张表的建表语句按依赖顺序重排一遍。5.3 现象main.py 连接数据库时报错提示 Authentication plugin caching_sha2_password cannot be loaded原因pymysql 与 MySQL 8.0 的加密握手不兼容缺少 cryptography 依赖库。解决执行 pip install cryptography 后重启程序。如果不想装额外依赖也可以在 MySQL 里把账号认证方式改回 mysql_native_password但我的建议是装 cryptography改认证方式会影响数据库安全性。5.4 现象run.sql 执行结果和实验报告里的截图数据对不上行数或数值不一致原因报告是某个时间点生成的但 setup.sql 的初始数据后来被改过或者 run.sql 在执行过程中用了 INSERT/UPDATE 修改了数据。解决对比报告截图和 run.sql 查询条件里的常量数值如果 WHERE 条件写的是具体学号或课程名直接用 SELECT 去库里核对。更稳妥的流程是跑 run.sql 前先重新执行一遍 setup.sql把数据恢复到初始状态保证报告、脚本、库三者完全一致。5.5 现象main.py 查询中文正常但新增或修改中文数据时乱码原因连接参数的 charset 与数据库字符集不一致。数据库是 utf8mb4连接却是 utf8写入时如果遇到表情符号或生僻字就会失败或乱码。解决把连接参数统一改成 charsetutf8mb4同时确认 setup.sql 建库语句里的 DEFAULT CHARACTER SET 也是 utf8mb4。三处一致——库、连接、客户端——中文问题基本绝迹。6. 答辩前最后一个动作把实验报告重新跑成一份「活的证明」很多课设的最大风险不是代码写了多少而是报告是报告、代码是代码两套东西对不上。答辩前最值得花时间的一步就是拿 run.sql 和 main.py 做一次回归验证把报告里的每一项结论重跑一遍。我的习惯是按章节对报告写了「平均分最高的课程」我就跑对应的 GROUP BY 查询把结果里第一行的课程名核对一遍报告贴了某个菜单功能的截图我就实际操作一遍 main.py 的对应选项确认打印字段和截图一致。任何一处对不上都改代码或改报告但绝不能两个都放着不动。报告里那些「系统测试」「性能分析」章节补起来也有取巧路径。把 run.sql 里几个核心查询的执行时间量出来用 SELECT 结果的行数说明查出了多少有效记录再对比加索引前后同一查询的耗时差异这三条证据就足以支撑起一个完整的测试章节。加索引的对比我一般这样做EXPLAIN SELECT * FROM score WHERE sno 20240001; CREATE INDEX idx_score_sno ON score(sno); EXPLAIN SELECT * FROM score WHERE sno 20240001;执行计划里 rows 字段从全表扫描的数值下降到接近 1就是一条能直接写进报告的结论。这个技巧不花一分钟但对答辩评分的「优化能力」维度几乎是决定性证据。从那以后我再做任何数据库课设都强制自己留出半小时做这一遍回归验证顺手把 EXPLAIN 的结果存进报告附录。这半小时从来不亏含糊不清的地方全在答辩前暴露出去了。希望帮到你。本文还有配套的精品资源点击获取