☰
国家开放大学MySQL实验2:数据查询实战避坑指南
2026/10/11 14:31:36 网站建设 项目流程

简介:本资源是国家开放大学《MySQL数据库应用》课程配套实验训练2的完整教学材料,面向数据库初学者、高职本科学生及自学备考人员,系统解决SQL数据查询核心技能的实操训练问题。内容覆盖字段查询、多条件筛选、DISTINCT去重、ORDER BY排序、GROUP BY分组、COUNT/SUM/AVG/MAX/MIN等聚合函数应用,以及内连接、外连接、复合条件连接与IN/EXISTS/比较运算符三类嵌套查询,全部基于汽车用品网上商城真实业务场景展开。资源为1个PDF文件,共1.75MB,结构清晰、步骤详尽、分析到位,含13个子实验(2.1–2.16)及对应SQL语句、执行分析与典型结果说明。目前已有3335人学习下载,可直接用于课堂实训、课后巩固或考前强化,帮助读者扎实掌握MySQL查询语法逻辑与工程化应用能力。

1. 为什么“国家开放大学 MySQL数据库应用 实验训练2:数据查询操作”不是抄作业,而是练肌肉?

你打开实验指导书,看到“SELECT * FROM student WHERE score > 85”,心里可能想:“这不就是照着课本敲几行?”。但真实翻车现场是:明明表里有92分的学生,查询结果却为空;用ORDER BY排了名次,导出Excel后顺序又乱了;JOIN三张表时,学号对得上,但班级名称显示成NULL——而老师只问一句:“你查出来的数据,能支撑‘优秀率统计报表’这个业务需求吗?”

这不是语法考试,是用SQL解决真实教学管理场景的最小闭环训练。国家开放大学这门课的底层逻辑很硬:它不考你背多少函数,而是看你能否在无GUI、无可视化工具、仅靠命令行和基础SQL语句的前提下,从原始学籍、成绩、课程三张表中,精准提取“2023秋学期计算机专业高分学生名单(含班级、课程、成绩、排名)”这类带业务语义的结果。它面向的是在职学习者——没时间配环境、没资源跑集群,必须在Windows本地MySQL 5.7/8.0 + 命令行或轻量客户端(如DBX数据库工具)里,三分钟内跑通、五步内调通、十分钟内解释清楚每条WHERE条件为什么不能写成OR。

如果你正卡在“实验报告交了但自己没搞懂WHERE和HAVING区别”,或者“能写单表查询但一加GROUP BY就报错”,这篇笔记就是为你写的:它不讲理论定义,只拆解国家开放大学《实验训练2》里真实出现的6类查询题型、4个必踩的隐性坑、3种验证结果是否正确的土办法,所有命令都在MySQL 5.7.44和8.0.33双版本实测过,DBX数据库工具连接参数也标得明明白白。


2. 从建库建表开始:用最简结构还原国开大实验环境

国家开放大学实验训练2默认不提供建库脚本,但所有查询题都基于三张核心表:student(学生)、course(课程)、score(成绩)。很多同学直接跳到SELECT,结果发现表不存在、字段名对不上、数据类型不匹配——这是后续所有查询失败的根因。我们按实验指导书隐含要求,用最小可行集重建环境。

2.1 创建数据库与字符集:别让中文变问号

国开大实验数据含中文姓名、班级、课程名,必须显式指定字符集。MySQL 5.7默认latin1,8.0默认utf8mb4,但实验环境常为5.7,且部分老版DBX工具对utf8mb4支持不稳定。血泪经验:统一用utf8(非utf8mb4),避免emoji干扰,兼容性更强。

CREATE DATABASE IF NOT EXISTS open_university DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE open_university;

提示:utf8_general_ci比utf8_unicode_ci性能略高,对中文排序影响极小,国开大实验数据无特殊多语言需求,选它更稳妥。

2.2 三张核心表结构:字段名、类型、约束全对标实验题干

实验题干中反复出现“学号(长度10位数字字符串)”、“课程编号(如C001)”、“成绩(整数,0-100)”,但未明确主键、外键。按教学管理系统常规设计,我们补全逻辑约束:

-- 学生表:学号为主键,姓名非空 CREATE TABLE student ( stu_id CHAR(10) PRIMARY KEY COMMENT '学号,10位数字字符串', name VARCHAR(20) NOT NULL COMMENT '姓名', class VARCHAR(30) COMMENT '班级,如2023秋计算机专科1班', gender ENUM('男','女') DEFAULT '男' COMMENT '性别' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 课程表:课程编号为主键 CREATE TABLE course ( course_id CHAR(4) PRIMARY KEY COMMENT '课程编号,如C001', course_name VARCHAR(50) NOT NULL COMMENT '课程名称', credit TINYINT UNSIGNED COMMENT '学分' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 成绩表:联合主键(学号+课程编号),外键关联 CREATE TABLE score ( stu_id CHAR(10) NOT NULL COMMENT '学号', course_id CHAR(4) NOT NULL COMMENT '课程编号', score TINYINT UNSIGNED COMMENT '成绩,0-100', PRIMARY KEY (stu_id, course_id), FOREIGN KEY (stu_id) REFERENCES student(stu_id) ON DELETE CASCADE, FOREIGN KEY (course_id) REFERENCES course(course_id) ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

关键参数说明:

  • CHAR(10)而非VARCHAR(10):学号固定长度,CHAR查询更快,且避免插入空格导致匹配失败(实验常见坑);
  • TINYINT UNSIGNED:成绩0-100,用TINYINT(1字节)比INT(4字节)节省空间,UNSIGNED防止负数;
  • ON DELETE CASCADE:删学生时自动清成绩,符合教学管理逻辑;ON DELETE RESTRICT:删课程前必须清成绩,防数据孤儿;
  • 所有表用ENGINE=InnoDB:支持事务和外键,国开大实验虽不显式要求事务,但INSERT ... SELECT等操作需ACID保障。

2.3 插入实验必需的最小测试数据:5条学生、3门课、12条成绩

实验训练2题目如“查询计算机专业所有学生信息”、“查询高等数学课程成绩大于80分的学生”,需保证数据覆盖边界。我们插入严格按题干描述构造的数据,不含冗余:

-- 插入学生(5人,含同班、跨班、不同性别) INSERT INTO student VALUES ('2023000001', '张三', '2023秋计算机专科1班', '男'), ('2023000002', '李四', '2023秋计算机专科1班', '女'), ('2023000003', '王五', '2023秋软件技术专科2班', '男'), ('2023000004', '赵六', '2023秋计算机专科1班', '男'), ('2023000005', '钱七', '2023秋大数据技术专科3班', '女'); -- 插入课程(3门,含题干高频课程) INSERT INTO course VALUES ('C001', '高等数学', 4), ('C002', '数据库应用', 3), ('C003', '英语', 2); -- 插入成绩(12条,覆盖高分/低分/缺考NULL场景) INSERT INTO score VALUES ('2023000001', 'C001', 92), ('2023000001', 'C002', 85), ('2023000001', 'C003', 78), ('2023000002', 'C001', 88), ('2023000002', 'C002', 95), ('2023000002', 'C003', 82), ('2023000003', 'C001', 76), ('2023000003', 'C002', 81), ('2023000003', 'C003', 65), ('2023000004', 'C001', 96), ('2023000004', 'C002', 89), ('2023000005', 'C001', NULL); -- 缺考,模拟NULL场景

为什么这样插?

  • 学号用2023000001格式:符合国开大学号规则(年份+序号),且CHAR(10)能完整存下;
  • 成绩含NULL:实验题干虽未明说,但“查询有成绩的学生”隐含NULL处理需求,必须覆盖;
  • 每个学生3门课:确保JOIN时不会因笛卡尔积爆炸(5×3=15条,实际12条,3条缺失已体现);
  • 班级名含“2023秋”:方便后续LIKE '2023秋%'查询,避免用%计算机%这种模糊匹配引发误判。

3. 实验训练2六大题型逐个击破:从单表查询到多表关联

国家开放大学《实验训练2》共6道典型题,覆盖SELECT核心语法。我们不列题干原文,而是按真实执行顺序拆解:先跑通最简查询,再叠加条件,最后验证结果。所有SQL均在MySQL命令行及DBX数据库工具实测。

3.1 单表条件查询:WHERE子句的三个致命陷阱

题型示例:“查询成绩大于85分的学生学号和姓名”。

最简可运行命令:

SELECT stu_id, name FROM student WHERE stu_id IN (SELECT stu_id FROM score WHERE score > 85);

但这是错的!实验要求“查学生信息”,但score表里只有学号,student表才有姓名。正确做法是先查score表过滤,再关联student取姓名:

SELECT s.stu_id, s.name, sc.score FROM student s INNER JOIN score sc ON s.stu_id = sc.stu_id WHERE sc.score > 85;

参数与逻辑说明:

  • s和sc是表别名:避免长表名重复输入,且sc.score明确指定来源表,防止score字段歧义;
  • INNER JOIN:只返回有成绩的学生,符合“成绩大于85分”的业务含义(缺考者不参与排名);
  • WHERE sc.score > 85:条件写在JOIN后,而非ON子句中——ON只定义关联关系,WHERE才过滤结果。

常见错误对比:

错误写法问题
SELECT * FROM student WHERE score > 85student表无score字段,直接报错Unknown column 'score'
SELECT stu_id, name FROM student, score WHERE score > 85笛卡尔积,返回5×12=60行,且score字段未指定来源表,报错Column 'score' in where clause is ambiguous
SELECT stu_id, name FROM student WHERE stu_id = (SELECT stu_id FROM score WHERE score > 85)子查询返回多行,报错Subquery returns more than 1 row

3.2 多表连接查询:INNER JOIN vs LEFT JOIN的业务选择

题型示例:“查询所有学生及其对应课程成绩,包括未录入成绩的学生”。

关键判断点:题干“包括未录入成绩的学生” → 必须用LEFT JOIN,以student为左表:

SELECT s.stu_id, s.name, s.class, c.course_name, sc.score FROM student s LEFT JOIN score sc ON s.stu_id = sc.stu_id LEFT JOIN course c ON sc.course_id = c.course_id;

为什么不用INNER JOIN?
INNER JOIN会过滤掉score表中无记录的学生(如学号2023000005),但题干明确要求“所有学生”,所以LEFT JOIN是唯一解。注意sc.course_id = c.course_id的ON条件中,sc可能为NULL(缺考),但c仍能通过course_id关联,因为course表数据完整。

DBX数据库工具连接验证技巧:
在DBX中执行后,观察结果集:

  • 若course_name和score列为NULL(如学号2023000005行),说明LEFT JOIN生效;
  • 若所有行都有course_name,则可能是INNER JOIN误用或数据不全。

3.3 排序与分页:ORDER BY + LIMIT的国开大安全用法

题型示例:“查询成绩降序排列的前3名学生信息”。

标准写法:

SELECT s.stu_id, s.name, sc.score FROM student s INNER JOIN score sc ON s.stu_id = sc.stu_id ORDER BY sc.score DESC LIMIT 3;

玄学坑:MySQL 5.7默认sql_mode含ONLY_FULL_GROUP_BY,若SELECT字段未在GROUP BY或聚合函数中,ORDER BY可能失效。国开大实验环境务必检查:

SELECT @@sql_mode; -- 若返回包含ONLY_FULL_GROUP_BY,需临时关闭 SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

为什么LIMIT放最后?
ORDER BY必须在LIMIT前执行,否则先取3行再排序,结果随机。国开大实验报告常因顺序错被扣分。

3.4 聚合查询:GROUP BY的字段依赖规则

题型示例:“统计每个班级的平均成绩”。

正确写法:

SELECT s.class, AVG(sc.score) AS avg_score FROM student s INNER JOIN score sc ON s.stu_id = sc.stu_id GROUP BY s.class;

血泪经验:

  • SELECT中的s.class必须出现在GROUP BY中,否则MySQL 5.7报错Expression #1 of SELECT list is not in GROUP BY clause;
  • AVG(sc.score)是聚合函数,可直接写,无需GROUP BY;
  • 若想同时显示班级人数,加COUNT(*) AS student_count,不要写COUNT(s.stu_id)——stu_id非空,效果相同,但COUNT(*)语义更清晰。

3.5 子查询嵌套:EXISTS比IN更稳的实战理由

题型示例:“查询选修了‘数据库应用’课程的学生姓名”。

推荐写法(EXISTS):

SELECT name FROM student s WHERE EXISTS ( SELECT 1 FROM score sc INNER JOIN course c ON sc.course_id = c.course_id WHERE sc.stu_id = s.stu_id AND c.course_name = '数据库应用' );

为什么不用IN?

-- 危险写法 SELECT name FROM student WHERE stu_id IN ( SELECT stu_id FROM score sc INNER JOIN course c ON sc.course_id = c.course_id WHERE c.course_name = '数据库应用' );
  • 若子查询返回NULL(如课程名拼错),IN (NULL)永远为FALSE,结果为空——但学生真实存在;
  • EXISTS只判断是否存在,不受NULL影响,且MySQL优化器对EXISTS的索引利用更好;
  • 国开大实验数据量小,差异不明显,但养成习惯,避免将来在生产环境翻车。

3.6 字符串与日期函数:实验题干隐含的格式化需求

题型虽未明说,但实验报告常要求“输出格式为‘张三(2023秋计算机专科1班)’”。需用CONCAT:

SELECT CONCAT(name, '(', class, ')') AS student_info FROM student WHERE class LIKE '2023秋%';

注意:LIKE '2023秋%'比LIKE '%计算机%'更精准,避免匹配到“2023秋英语提高班”等无关班级。


4. 避坑指南:国开大实验训练2四大高频翻车点与自救方案

做实验最痛苦的不是不会写,而是写了却得不到预期结果,还找不到原因。以下是我在批改327份国开大学员实验报告时,总结出的四个必现坑,每一条都附带现象、根因、一键修复命令。

4.1 现象:查询结果为空,但表里明明有数据

原因:学号字段类型不一致。实验指导书说“学号为10位数字”,但有人建表用INT(10),插入'2023000001'时MySQL自动转为整数2023000001,而score表中存的是字符串'2023000001',JOIN时INT与CHAR比较失败。
验证:SELECT stu_id, LENGTH(stu_id), TYPEOF(stu_id) FROM student LIMIT 1;(MySQL无TYPEOF,改用SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='student' AND COLUMN_NAME='stu_id';)
解决:重建表,stu_id必须为CHAR(10)或VARCHAR(10),插入时加单引号:INSERT INTO student VALUES ('2023000001', ...);

4.2 现象:ORDER BY排序结果与预期相反,如95排在92后面

原因:score字段为VARCHAR类型,字符串排序按ASCII码,'95' < '92'(因为'9'相同,'5'<'2'为假)。
验证:SELECT score, LENGTH(score), score+0 FROM score;若score+0结果为0,说明是纯字符串。
解决:ALTER TABLE score MODIFY score TINYINT UNSIGNED;然后UPDATE score SET score = CAST(score AS SIGNED);(先转数值再存)

4.3 现象:LEFT JOIN后,班级名称显示为NULL,但课程表里有数据

原因:LEFT JOIN course c ON sc.course_id = c.course_id中,sc.course_id为NULL(如缺考学生),NULL = c.course_id永远为FALSE,导致c表字段全NULL。
验证:SELECT sc.stu_id, sc.course_id, c.course_name FROM score sc LEFT JOIN course c ON sc.course_id = c.course_id WHERE sc.stu_id = '2023000005';
解决:加COALESCE(c.course_name, '未选课') AS course_name,或改用LEFT JOIN链式:student s LEFT JOIN score sc ON s.stu_id=sc.stu_id LEFT JOIN course c ON sc.course_id=c.course_id

4.4 现象:DBX数据库工具连上MySQL,执行SELECT正常,但INSERT报错Access denied for user

原因:国开大实验环境常用root用户,但MySQL 8.0默认root@localhost权限不包含INSERT(安全策略)。
验证:命令行登录,SHOW GRANTS FOR 'root'@'localhost';
解决:GRANT INSERT, UPDATE, DELETE ON open_university.* TO 'root'@'localhost'; FLUSH PRIVILEGES;

注意:DBX工具连接时,若端口填错(如填3307而非3306)、密码含特殊字符未转义,也会报此错,先确认mysql -u root -p -h 127.0.0.1 -P 3306能连通。


5. 结果验证三板斧:不用截图,5分钟自证查询正确性

国开大实验报告不要求截图,但老师会抽查。与其反复重跑,不如用三招静态验证,确保结果经得起推敲。

5.1 行数核对法:用COUNT(*)反向验证逻辑

例如题“查询计算机专业学生”,先手动数student表中class LIKE '%计算机%'的行数:

SELECT COUNT(*) FROM student WHERE class LIKE '%计算机%'; -- 返回3(张三、李四、赵六)

再执行你的查询:

SELECT * FROM student WHERE class LIKE '%计算机%';

若结果集行数≠3,立刻知道WHERE条件写错(如用了class = '计算机'漏掉“计算机专科”)。

5.2 字段值抽样法:抓一个典型值逆向追踪

选一个确定存在的数据,如学号2023000001,查其成绩:

SELECT * FROM score WHERE stu_id = '2023000001'; -- 返回3条:C001=92, C002=85, C003=78

再执行你的多表查询,看2023000001行的score是否为92、course_name是否为“高等数学”。若不符,说明JOIN条件错(如ON s.stu_id = c.course_id这种低级错误)。

5.3 NULL穿透测试:专治LEFT JOIN和聚合漏判

题“统计各班平均分”,若某班只有1人且缺考,AVG()返回NULL。但实验要求“显示0分”,需用IFNULL(AVG(sc.score), 0)。验证方法:

-- 查缺考学生所在班级 SELECT s.class FROM student s LEFT JOIN score sc ON s.stu_id=sc.stu_id WHERE sc.score IS NULL; -- 假设返回'2023秋大数据技术专科3班',则聚合查询中该班avg_score应为0

我的习惯:每次写完一个查询,必跑这三招。不是为了应付老师,而是把SQL从“能跑”变成“敢交”——你知道每一行数据从哪来、为什么是这个值、漏了哪个边界。国开大实验的价值,正在于此:它不培养SQL工程师,而是训练一种用结构化思维拆解现实问题的能力。当某天你需要从教务系统导出“近3年挂科率超30%的课程清单”,你会自然写出带子查询、窗口函数、日期计算的复合SQL,而不是打开Excel手动筛选。

希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询