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

研一数据库大作业:学生成绩管理系统SQL完整实现与答辩要点

研一数据库大作业:学生成绩管理系统SQL完整实现与答辩要点 ★ FEATURED ARTICLE
简介这份资源是北邮研一数据库课程大作业的完整详解文档面向计算机相关专业研究生及需要完成数据库课程设计的学习者围绕学生成绩管理系统的设计与实现展开可帮助读者理清从需求分析到程序落地的完整思路。内容涵盖功能需求与数据需求梳理、Course、Student、Sc、Teacher 四张表的结构设计、主外键约束与一对多关系处理、局部与全局 ER 图绘制、逻辑结构设计与数据字典以及建库建表 SQL 语句等关键环节并涉及成绩维护、教师信息管理、不及格学生名单统计和无教学任务教师查询等典型功能。资源包共 1 个 docx 文件约 503KB以文字与图表形式系统呈现设计过程便于对照课程要求逐步复现。目前已有 607 人学习适合作为数据库大作业的参考范本与查漏补缺材料。1. 学生成绩管理系统一份研一数据库大作业的完整交付路径高校教务场景里有个很典型的需求授课教师录成绩、学生自己查成绩、教务处统计不及格名单、还要查哪些老师这学期没排课。四个诉求看着简单落到数据库上就是四张表、一组约束、一批视图和存储过程的事。这份研一数据库大作业要解决的就是把「学生成绩管理系统」从需求分析一路做到可运行的 SQL 实现适合正在赶数据库课设、毕设开题或者需要交一份完整数据库设计文档的人直接参考。它不追求花哨的前端重点在关系模型是否站得住、约束是否写全、查询是否经得起追问——这恰恰是答辩时最容易被盯的地方。2. 需求与数据建模四张表怎么撑起教务场景2.1 从教务科的四句话反推功能边界需求原文里教务处只提了四件事教师录成绩、学生查成绩、统计不及格名单、查无教学任务教师。很多人一上来就画一堆表结果做到一半发现「无教学任务教师」这个查询根本落不下去——因为课程表里如果只存了课程名没有任课教师字段这个需求就是空中楼阁。所以第一步不是建表是把每句话翻译成「需要哪些字段、哪些表之间要能连起来」。我的做法是先列一张需求-数据对照把每条功能需求映射到具体的表和连接条件功能需求涉及表关键连接/条件教师录入成绩sc按 snocno 定位写 degree学生查询成绩sc、coursesc.cno course.cno统计不及格名单sc、student、coursedegree 60按 cno 分组查无教学任务教师teacher、courseteacher.tno 不在 course.tno 中这张表看着朴素但它决定了后面所有设计的走向。比如「无教学任务教师」要求 course 表必须带 tno 字段否则你只能靠一张额外的授课关系表来补模型就复杂了一层。原文的 course 表设计里确实带了 tno说明设计者是先想清楚查询再定字段的这个顺序值得照搬。2.2 四张表的字段取舍与主外键落点原文给了 course、student、sc、teacher 四张表字段和类型都比较明确。这里把关键约束整理成一张数据字典方便直接对着建表表主键关键字段与约束coursecnocno char(5) 非空cname varchar(20) 非空tno char(3) 非空studentsnosno char(9) 主键ssex 取值男/女smajor、sclass 可空sc(sno, cno)组合主键degree decimal(4,1)CHECK 0~100teachertnotno char(3) 主键tsex 取值男/女tdept char(16)有几个细节容易被忽略。第一sc 表的 degree 用 decimal(4,1) 而不是 int是因为成绩可能有 86.5 这种小数用整型会丢精度答辩时被问「为什么不用 float」也有话说——decimal 是精确小数float 有二进制误差成绩这种要参与统计平均的字段用 decimal 更稳。第二sc 的组合主键天然保证了「一个学生一门课只有一条成绩记录」不需要额外加唯一索引这是关系模型自带的约束力。第三student 的 sno 在原文里出现过 char(9) 和 char(10) 两种写法建表时统一成一种否则外键类型不一致会直接报错这是血泪经验。2.3 ER 关系到关系模式的转换检查原文的 ER 图里学生和课程是多对多选修教师和课程是一对多讲授。多对多必须落成一张中间表这就是 sc 的由来一对多则把「一」端的主键放到「多」端做外键所以 course 表里带 tno。转换完之后要做一次范式检查四张表都满足第三范式没有非主属性对候选码的传递依赖。这里有个常被问的点course 表里 cname 依赖 cnotno 也依赖 cno两者之间没有依赖关系所以不违反 3NF。但如果有人把教师姓名也塞进 course 表那就出现 cno → tno → tname 的传递依赖了必须拆回 teacher 表。检查函数依赖集的时候把每个表的候选码写出来逐个属性问「它完全依赖于整个码吗、只依赖码吗」两个问题都过范式就站住了。3. 建库建表与约束落地把设计文档变成能跑的 SQL3.1 建表语句与 CHECK 约束的写法设计文档再漂亮建表语句跑不通就是零分。下面这段是四张表的完整 DDL注意 CHECK 约束和主键的写法CREATE DATABASE test; USE test; CREATE TABLE teacher ( tno CHAR(3) NOT NULL, tname VARCHAR(8), tsex CHAR(2), tdept CHAR(16), CONSTRAINT pk_teacher PRIMARY KEY (tno), CONSTRAINT ck_tsex CHECK (tsex IN (男,女)) ); CREATE TABLE course ( cno CHAR(5) NOT NULL, cname VARCHAR(20) NOT NULL, tno CHAR(3) NOT NULL, CONSTRAINT pk_course PRIMARY KEY (cno), CONSTRAINT fk_course_teacher FOREIGN KEY (tno) REFERENCES teacher(tno) ); CREATE TABLE student ( sno CHAR(9) NOT NULL, sname CHAR(8), ssex CHAR(2), smajor CHAR(20), sclass CHAR(10), CONSTRAINT pk_student PRIMARY KEY (sno), CONSTRAINT ck_ssex CHECK (ssex IN (男,女)) ); CREATE TABLE sc ( sno CHAR(9) NOT NULL, cno CHAR(5) NOT NULL, degree DECIMAL(4,1), CONSTRAINT pk_sc PRIMARY KEY (sno, cno), CONSTRAINT fk_sc_student FOREIGN KEY (sno) REFERENCES student(sno), CONSTRAINT fk_sc_course FOREIGN KEY (cno) REFERENCES course(cno), CONSTRAINT ck_degree CHECK (degree 0 AND degree 100) );建表顺序有讲究teacher 和 student 先建course 依赖 teachersc 依赖 student 和 course所以 sc 必须最后建。如果顺序反了外键引用一张还不存在的表MySQL 会直接拒绝。原文里 course 表没有显式写外键我这里补上了因为「无教学任务教师」的查询依赖 tno 的引用完整性——如果 course.tno 能随便填一个不存在的教师号那个查询的结果就不可信了。3.2 视图把高频查询封装成可复用的入口原文建了一个 v_student 视图查选修「科学导论」的学生学号、姓名、成绩。视图的价值在于把三表连接固化下来后续查询只面对一个「宽表」。写法如下CREATE VIEW v_student AS SELECT A.sno, A.sname, C.degree FROM student A JOIN sc C ON A.sno C.sno JOIN course B ON C.cno B.cno WHERE B.cname 科学导论;这里用 JOIN 而不是原文的逗号连接加 WHERE两种写法结果一样但 JOIN 的可读性更好连接条件和过滤条件分得清答辩时讲起来也顺。视图建好后SELECT * FROM v_student;就能直接出结果。需要注意的是这个视图是只读的——它包含连接MySQL 不允许对这种视图做 INSERT/UPDATE所以原文另建了一个单表的 view_sc 来做插入演示这个区分要讲清楚不然会被问「为什么这个视图不能插数据」。3.3 存储过程与触发器把业务规则沉到数据库层存储过程适合封装「带参数的固定查询」。原文有两个例子一个是查某班级学生一个是统计某学生的选课数。第二个更能体现 OUT 参数的用法DELIMITER // CREATE PROCEDURE num_sc(IN tmp_sno CHAR(9), OUT count_num INT) READS SQL DATA BEGIN SELECT COUNT(*) INTO count_num FROM sc WHERE sno tmp_sno; END // DELIMITER ; CALL num_sc(120210332, cnt); SELECT cnt;IN是入参OUT是出参调用时用一个用户变量cnt接结果。READS SQL DATA是告诉数据库这个存储过程只读不写属于权限声明生产环境里有助于做权限收敛。触发器则用来做「删除留痕」student 表删人之前先把学号姓名写进 delstudent 备份表。CREATE TABLE delstudent LIKE student; ALTER TABLE delstudent ADD COLUMN del_time DATETIME; CREATE TRIGGER trig_student AFTER DELETE ON student FOR EACH ROW INSERT INTO delstudent(sno, sname, del_time) VALUES (OLD.sno, OLD.sname, NOW());OLD关键字指代被删除的那一行AFTER DELETE表示删除动作完成后触发。这里我加了删除时间字段比原文只存学号姓名更实用——真出了误删事故能查到是什么时候删的。触发器是把双刃剑它让删除操作「悄悄」多了一步写入调试时如果不知道有触发器会以为是数据自己冒出来的这点后面避坑章节会展开。4. 复杂查询与统计口径教务处那几张报表怎么出4.1 不及格名单与平均分的统计写法教务处最关心的两张报表某门课不及格的学生信息、某门课的平均分。不及格查询要三表连接因为要同时拿到学生信息和课程定位SELECT A.sno, A.sname, A.ssex, A.smajor, A.sclass, B.degree FROM student A JOIN sc B ON A.sno B.sno JOIN course C ON B.cno C.cno WHERE C.cno C03 AND B.degree 60 ORDER BY A.sno;平均分则简单但要注意AVG会忽略 NULL 值——如果某学生选了课但成绩还没录degree 是 NULL这个 NULL 不会进分母。如果教务处的口径是「按选课人数算平均」那就得用SUM(degree)/COUNT(*)而不是AVG(degree)两者在有空成绩时结果不同。这个口径差异答辩时经常被追问提前想清楚。4.2 无教学任务教师一个反连接查询「查没有教学任务的老师」本质是反连接teacher 表里存在、但 course 表里找不到对应 tno 的记录。三种写法推荐 NOT EXISTSSELECT tno, tname, tdept FROM teacher T WHERE NOT EXISTS ( SELECT 1 FROM course C WHERE C.tno T.tno );也可以用NOT IN但当子查询结果里出现 NULL 时NOT IN会返回空集——这是 SQL 三值逻辑的经典坑。NOT EXISTS对 NULL 免疫语义也更贴近「不存在这样一门课」所以我一般优先用它。如果数据量小LEFT JOIN ... WHERE C.tno IS NULL也能出结果但可读性不如 NOT EXISTS 直白。4.3 索引该建在哪几个字段上原文提到「建立索引」但没展开。按这套查询模式索引落点很明确sc 表的(sno, cno)组合主键自带索引按学号查成绩、按课程查成绩都能命中course 表的 tno 上建议加一个普通索引因为反连接查询要按 tno 做匹配student 表的 sclass 如果经常按班级筛人也值得加。索引不是越多越好每加一个都会拖慢写入成绩录入是写操作索引要克制。CREATE INDEX idx_course_tno ON course(tno); CREATE INDEX idx_student_class ON student(sclass);建完可以用EXPLAIN看执行计划确认查询走了索引而不是全表扫描。这一步在答辩演示时很加分——不是「我建了索引」而是「我验证了索引被用上」。5. 避坑与排查这套设计里最容易翻车的五个点5.1 外键类型不一致导致建表失败现象建 sc 表时报errno 150外键约束加不上。原因student.sno 是 char(9)sc.sno 写成了 char(10)长度不一致MySQL 拒绝建立外键。解决把所有引用 sno 的字段统一成 char(9)cno 统一 char(5)建表前先对一遍类型清单。这个错我见过太多次本质是设计文档里两处写法不统一抄的时候没对齐。5.2 触发器导致删除操作「删不干净」现象删了一个学生student 表里没了但 sc 表里他的成绩还在查成绩时出现孤儿记录。原因只给 student 建了 AFTER DELETE 触发器写备份表没处理 sc 表的外键级联。解决要么在 sc 的外键上加ON DELETE CASCADE要么在触发器里补一条删除 sc 的语句。我一般选前者让数据库自己保证引用完整性比在触发器里手写删除可靠。5.3 视图更新报「不可更新视图」现象对包含 JOIN 的 v_student 执行 INSERT报错。原因多表连接视图在 MySQL 里默认不可更新。解决插入操作走基表或单表视图如原文的 view_sc别指望连接视图能写。设计文档里要把「哪些视图只读、哪些可写」标清楚不然演示时当场翻车。5.4 CHECK 约束在旧版本被静默忽略现象插了一条 degree 120 的记录居然成功了。原因MySQL 8.0.16 之前的版本解析 CHECK 但不强制执行约束形同虚设。解决确认数据库版本旧版本用触发器或应用层校验兜底新版本则放心用 CHECK。答辩环境如果是学校统一装的旧版 MySQL这一条一定要提前测。5.5 存储过程 DELIMITER 没恢复导致后续语句报错现象建完存储过程后面的普通 SQL 全部报语法错误。原因DELIMITER //把结束符改成了//忘了改回;。解决每个存储过程定义结束后紧跟DELIMITER ;养成成对写的习惯。Navicat 这类图形工具对 DELIMITER 的处理和命令行不同同一段脚本两边跑结果可能不一样交付前在目标环境里完整跑一遍。6. 验收与答辩怎么证明这套库真的能用验收不是「表建出来了」就完事要拿需求逐条打勾。我一般准备一张验收清单每条需求对应一条可执行的 SQL 和预期结果现场跑给老师看验收项验证 SQL 要点预期成绩录入INSERT INTO sc 后 SELECT 回查记录存在degree 正确学生查成绩查 v_student 或按 sno 连接返回课程名与分数不及格名单degree 60 三表连接名单与手工核对一致无教学任务教师NOT EXISTS 反连接结果不含已排课教师约束有效性插 degree120被 CHECK 拒绝触发器删学生后查 delstudent备份表有记录答辩时最容易被问的三个问题提前准备好答案为什么 sc 用组合主键而不是自增 id答业务上学生课程天然唯一组合主键直接表达这个约束省一个字段也省一次唯一索引为什么成绩用 decimal 不用 float答精确小数统计算术不引入二进制误差无教学任务教师为什么不用 NOT IN答子查询含 NULL 时 NOT IN 返回空集NOT EXISTS 语义更稳。演示顺序也有讲究先跑建表脚本证明 DDL 完整再跑几条插入证明约束生效然后跑视图和存储过程证明封装能力最后跑反连接查询证明能回答教务处的原始问题。整个流程控制在五分钟内每条语句都有明确目的不堆砌。从那以后我每次交数据库作业都会在答辩前一晚把全部脚本在一个干净数据库里从头跑一遍包括删库重建——因为「在我机器上是好的」这句话在老师面前一文不值。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站