
简介本资源是国家开放大学《MySQL数据库应用》课程配套实验训练材料面向数据库初学者、高职本科学生及备考数据库认证的学习者系统覆盖SQL数据查询核心技能。内容紧扣教学实践完整包含字段查询、多条件WHERE筛选、DISTINCT去重、ORDER BY排序、GROUP BY分组、COUNT/SUM/AVG/MAX/MIN等聚合函数应用以及INNER JOIN、LEFT JOIN、复合连接与IN/EXISTS/比较运算符三类嵌套查询共16个递进式实验全部基于汽车用品电商真实业务场景设计。资源为单文件PDF文档1.75MB结构清晰、分析详尽每个实验均含需求说明、表结构分析与SQL实现逻辑便于边学边练、理解底层原理。目前已有3339人学习下载是掌握MySQL查询语法、提升实战查询能力的优质入门级实训资料。1. 这不是“背命令”而是让数据库听懂你说话MySQL 查询到底在干啥你有没有试过在手机里翻通讯录找一个人结果输错一个字就怎么也找不到或者在购物App里点“按销量排序”页面唰一下全变了——背后其实都是同一件事告诉数据“我要看什么、按什么条件、怎么排、别重复”。MySQL 数据库的查询操作就是这么一回事它不神秘不是程序员专属黑匣子而是一套你和数据之间最直接的对话语言。这份《国家开放大学 MySQL数据库应用 实验训练2数据查询操作》就是专门带你从“只会点按钮”升级到“能开口提要求”的实战手册。它不讲服务器怎么装、不聊索引原理有多深就聚焦在你每天都会遇到的真实场景查某个商品、看某天卖了多少单、找出最贵的商品、知道谁买了最多东西、甚至把两个表格里的信息自动拼在一起……所有例子都来自一个汽车用品商城的模拟业务有商品、订单、用户、评论这些你一听就懂的实体。如果你刚学完建表、插数据正卡在“接下来怎么把数据用起来”这一步或者工作中常要导Excel、跑报表却总得求人写SQL又或者准备考数据库相关证书被“GROUP BY”“JOIN”这些词绕晕了——那这份实验训练就是为你量身定做的第一块踏脚石。它不逼你死记硬背而是让你每写一行SELECT都清楚自己在对数据库下什么指令、为什么这样写才对。2. 先搞懂一个核心动作SELECT 是怎么把数据“喊出来”的2.1 字段查询从一张表里精准抓取你要的信息这是所有查询的起点就像去图书馆借书先确定去哪个书架哪张表再报出书名字段名。实验2.1里有两个例子查“挡风玻璃”的商品信息、查ID为1的订单。它们的共同点是——只用一张表就能搞定。比如商品表假设叫products里有id,name,price,category_id等字段你想看“挡风玻璃”的全部信息SQL就是SELECT * FROM products WHERE name 挡风玻璃;提示“*”代表“所有字段”初学时可以先这么写等熟悉了再换成具体字段名比如SELECT id, name, price FROM products...这样更清晰、也更高效。再比如订单表假设叫orders里有order_id,user_id,total_amount,order_date查ID为1的订单SELECT * FROM orders WHERE order_id 1;这里的关键是WHERE子句——它像一道门禁只放行符合条件的记录。“order_id 1”就是开门的钥匙。注意数字不用加引号但文字如挡风玻璃必须用单引号包裹这是新手最容易翻车的第一步。2.2 多条件查询用“而且”“或者”组合你的要求现实中的需求很少只靠一个条件。实验2.2要查“促销中且价格小于1000”的商品这就需要把两个条件“绑在一起”。SQL用AND表示“而且”用OR表示“或者”。假设商品表里有个字段叫is_on_sale1表示促销0表示不促销价格字段叫price那么SELECT * FROM products WHERE is_on_sale 1 AND price 1000;这里AND是关键数据库会先筛出所有促销的商品再从这批里挑出价格1000的。如果写成OR结果就会变成“促销的”或“价格1000的”——哪怕不促销、价格还很高也会被拉进来完全偏离本意。注意当条件变多时括号能帮你理清逻辑。比如“促销且价格1000或者新品且库存50”就要写成WHERE (is_on_sale 1 AND price 1000) OR (is_new 1 AND stock 50)。别小看括号它能避免很多玄学bug。2.3 DISTINCT解决“怎么老看到同一个名字”的烦恼实验2.3里查“对商品ID为1发表过评论的用户ID”表面看很简单但实际数据里一个用户可能给同一商品评了5次论。如果直接SELECT user_id FROM comments WHERE product_id 1;结果里user_id1001会出现5次。你真正想知道的是“有哪些人评过”不是“评了多少次”。这时候DISTINCT就是后悔药SELECT DISTINCT user_id FROM comments WHERE product_id 1;它像一台复印机的“去重模式”只输出不重复的值。同样查会员创建年份比如2020、2021、2021、2022用SELECT DISTINCT YEAR(create_time) FROM users;就能干净列出2020、2021、2022三个年份而不是一堆重复数字。2.4 ORDER BY让结果不再乱糟糟按你想要的顺序排好队实验2.4要求“类别ID为1的商品按商品ID降序排列”。默认查出来的数据是数据库存储的物理顺序毫无规律。ORDER BY就是给结果列队的教官。SELECT * FROM products WHERE category_id 1 ORDER BY id DESC;DESC是“降序”从大到小对应的是ASC升序可省略。这里ORDER BY id DESC告诉数据库“先把满足条件的记录挑出来再按id字段从高到低排队”。如果想按商品名称字母顺序排就写ORDER BY name ASC。提示ORDER BY必须放在WHERE之后、LIMIT如果有的话之前顺序错了会报错。这是新手第二容易踩的坑。2.5 GROUP BY从“看一条记录”升级到“看一群记录的总结”实验2.5要查“每个用户的消费总金额”。这不再是查某个人花了多少而是要把所有订单“按用户ID分组”再对每组算总和。这就是GROUP BY的使命。SELECT user_id, SUM(total_amount) AS total_spent FROM orders GROUP BY user_id;GROUP BY user_id像一把尺子把所有订单按user_id归成一摞一摞SUM(total_amount)则是对每一摞里的total_amount求和AS total_spent是给计算结果起个易懂的名字别名不然列名会是SUM(total_amount)看着费劲。注意SELECT后面除了聚合函数如SUM,COUNT其他字段如user_id必须出现在GROUP BY子句里。如果漏写user_id数据库会直接报错——这是强制你明确“按什么分组”避免歧义。3. 避坑指南新手写查询时最常卡住的5个地方3.1 现象运行SQL后报错“Unknown column xxx in field list”原因你写的字段名在表里根本不存在可能是拼错了或者大小写敏感某些系统区分大小写或者你查的表压根没这个字段。解决先用DESCRIBE table_name;或SHOW COLUMNS FROM table_name;查看表结构确认字段名完全一致。比如想查product_name但实际字段叫name那就得改过来。3.2 现象WHERE条件写了但结果还是把所有数据都查出来了原因最常见的原因是字符串条件忘了加单引号。比如WHERE name 挡风玻璃没引号数据库会把它当成字段名或变量而不是文字值导致条件失效。解决所有文字值包括中文、英文、数字字符串如2023-01-01必须用单引号包裹。数字值如ID、价格不用引号。记一句口诀“文字戴帽子引号数字光脑袋”。3.3 现象用了DISTINCT结果还是有重复原因DISTINCT是对整行去重不是对某一个字段。比如SELECT DISTINCT user_id, comment_text FROM comments只要user_id和comment_text的组合不同就算两行。如果只想看不重复的user_id就必须只写SELECT DISTINCT user_id ...不能把其他字段带上。解决明确你的目标是“去重哪个字段”SELECT后只保留那个字段或加上必要的关联字段其他无关字段先去掉。3.4 现象ORDER BY 排序没生效或者报错“Expression #1 of SELECT list is not in GROUP BY clause”原因在GROUP BY查询里SELECT后的非聚合字段如果没有出现在GROUP BY中MySQL 8.0 默认会拒绝执行严格模式。比如SELECT user_id, name, SUM(total) FROM orders GROUP BY user_idname不在GROUP BY里就会报错。解决要么把name加进GROUP BYGROUP BY user_id, name要么确认name和user_id是一一对应的比如用户表里查那就该换表查而不是在订单表里硬加。3.5 现象JOIN连接后结果行数远超预期甚至出现大量NULL原因没写ON条件或者ON条件写错了导致笛卡尔积A表10行 × B表20行 200行无意义组合。或者用了LEFT JOIN却把过滤条件写在WHERE里如WHERE b.status active这会把左表没匹配的行也过滤掉失去外连接意义。解决JOIN后必须跟ON指定关联字段如ON a.user_id b.id过滤右表的条件要写在ON里ON b.status active而不是WHERE。4. 聚合函数与连接查询从“看数据”到“读懂数据背后的故事”4.1 COUNT/SUM/AVG/MAX/MIN五位数据统计员各司其职实验2.6到2.10集中展示了五个最常用的聚合函数它们不是独立存在的而是和GROUP BY搭配使用才能发挥威力。COUNT()数数量SELECT COUNT(*) FROM categories;查类别总数SELECT DATE(order_date) as day, COUNT(*) as order_count FROM orders GROUP BY DATE(order_date);查每天接单数DATE()函数把时间戳转成日期。SUM()算总和SELECT DATE(order_date) as day, SUM(total_amount) as daily_sales FROM orders GROUP BY DATE(order_date);查每天销售额。AVG()算平均SELECT AVG(total_amount) as avg_order FROM orders;所有订单平均金额。注意AVG会自动忽略NULL值很贴心。MAX()/MIN()找极值SELECT MAX(quantity) as max_stock FROM products;最大库存SELECT MIN(price) as lowest_price FROM products;最低价格。有趣的是MAX(name)会返回字母顺序最后的名字如Zhang SanMIN(name)返回最前的如Adam Lee这是文本比较的自然结果。4.2 内连接INNER JOIN只留“两边都有”的交集实验2.11是典型场景查订单的发出者名字。订单表有user_id用户表有id和username但两张表的数据是分开存的。INNER JOIN就是把它们“缝合”起来SELECT o.order_id, u.username FROM orders o INNER JOIN users u ON o.user_id u.id;这里o和u是表的别名让语句更短ON o.user_id u.id是缝合线指明用什么字段连。结果只包含那些“订单表里有user_id且用户表里真有这个id”的记录。如果某个订单的user_id在用户表里找不到这条订单就不会出现在结果里。4.3 外连接LEFT/RIGHT JOIN确保“主表数据不丢失”实验2.12要“列出所有用户ID以及他们的评论如果有”。这时就不能用INNER JOIN否则没发过评论的用户就消失了。LEFT JOIN保证左表用户表所有行都在右表评论表匹配不到的对应字段填NULLSELECT u.id as user_id, c.comment_text FROM users u LEFT JOIN comments c ON u.id c.user_id;RIGHT JOIN逻辑相反以右表为主。但实践中LEFT JOIN更常用因为习惯把“主体表”放左边比如查用户用户表就是主体。4.4 复合条件连接在连接基础上再加一层筛选实验2.13要查“用户ID为1的客户的订单和客户名”。这其实是两步先连接订单和用户表再过滤user_id 1。可以写成SELECT o.order_id, u.username FROM orders o INNER JOIN users u ON o.user_id u.id WHERE u.id 1;注意WHERE放在JOIN之后是对连接后的临时结果再筛选。如果把u.id 1写进ON里ON o.user_id u.id AND u.id 1效果一样但可读性稍差。初学建议ON只管“怎么连”WHERE只管“连完后要哪些”。4.5 嵌套查询子查询让数据库“先算一步再算下一步”当需求无法用单层JOIN或WHERE表达时子查询就派上用场。实验2.14用IN查“订购商品ID为1的订单的用户ID”SELECT user_id FROM orders WHERE order_id IN ( SELECT order_id FROM order_items WHERE product_id 1 );内层查询SELECT order_id FROM order_items WHERE product_id 1先找出所有含商品1的订单ID外层再用这些ID去订单表里找对应用户。NOT IN逻辑相反。实验2.16的EXISTS更高效尤其数据量大时SELECT * FROM users WHERE EXISTS ( SELECT 1 FROM orders WHERE orders.user_id users.id );它不关心子查询返回什么值只判断“是否存在匹配行”一找到就停比IN更快。5. 从“照着抄”到“自己写”第一个完整案例跑通指南5.1 准备工作三步快速搭建实验环境你不需要装服务器、配环境。国家开放大学这份实验训练配套的通常是轻量级本地数据库工具如MySQL Workbench、DBeaver或网页版练习平台。按以下三步走下载并导入示例数据库资源包里会有.sql文件比如car_shop_db.sql里面包含建表语句CREATE TABLE和测试数据INSERT INTO。在你的MySQL客户端里新建一个数据库如car_shop然后执行这个.sql文件。验证表是否建好运行SHOW TABLES;应该能看到products,orders,users,comments等表名再选一张表如DESCRIBE products;确认字段名和类型符合实验描述。打开查询窗口在客户端里新建一个SQL标签页就可以开始敲代码了。别怕报错每一次报错都是数据库在教你语法。5.2 动手完成实验2.5GROUP BY SUM的完整流程目标查询每个用户的消费总金额。第一步确认数据在哪从摘要知道订单信息在orders表字段有user_id用户ID、total_amount订单总价。第二步写出基础框架SELECT要什么用户ID和总金额 →SELECT user_id, SUM(total_amount)从哪查orders表 →FROM orders怎么分组按用户ID →GROUP BY user_id第三步补全并执行SELECT user_id, SUM(total_amount) AS total_spent FROM orders GROUP BY user_id;运行后你会看到类似这样的结果user_idtotal_spent10012580.0010021200.501003890.00第四步理解每一行第一行user_id1001, total_spent2580.00意味着用户1001的所有订单总价加起来是2580元。数据库自动把他的所有订单找出来、加总、打包成一行。这就是GROUP BY的魔力——它把分散的数据聚合成有意义的汇总。5.3 进阶给结果加点“人情味”上面的结果只有ID不知道用户是谁。我们可以用INNER JOIN把用户姓名加上SELECT u.username, SUM(o.total_amount) AS total_spent FROM orders o INNER JOIN users u ON o.user_id u.id GROUP BY u.id, u.username;这里GROUP BY u.id, u.username是因为SELECT里有u.username且u.id和u.username是一一对应的一个ID只有一个名字所以必须一起分组。结果会是usernametotal_spent张三2580.00李四1200.50王五890.00看数据立刻变得可读了。这就是从“机器语言”走向“业务语言”的关键一步。6. 下一步学什么一份不烧脑、不走弯路的进阶路线图6.1 先巩固把这20个实验当“肌肉记忆”来练别急着学新东西。把实验2.1到2.19每个都亲手敲一遍、改一遍、错一遍。比如实验2.4ORDER BY做完后试试把DESC换成ASC再把ORDER BY id换成ORDER BY price看看结果怎么变实验2.11INNER JOIN做完马上做实验2.12LEFT JOIN对比结果差异。我的血泪经验是前50次手动输入比看100遍文档记得牢。你会慢慢发现SELECT是主干WHERE是枝杈GROUP BY是分叉JOIN是嫁接——它们不是孤立的命令而是一个有机整体。6.2 再延伸三个最值得优先掌握的“实用技能”当你能流畅写出GROUP BY和JOIN后立刻转向这三个高频场景它们能立刻提升你的工作效率技能为什么重要怎么开始练WHERE 函数组合现实中条件很少是简单相等。比如“查今年的订单”要用WHERE YEAR(order_date) YEAR(NOW())“查用户名含‘张’的”用WHERE username LIKE %张%。从实验2.4的“今年新增会员”入手把WHERE create_time 2023-01-01换成WHERE YEAR(create_time) 2023再试试LIKE和BETWEEN。多表JOIN嵌套一个查询常涉及3张以上表。比如“查用户买的商品名称和价格”需连users→orders→order_items→products。在实验2.11基础上把orders INNER JOIN users扩展成orders INNER JOIN users INNER JOIN order_items INNER JOIN products一步步加每次加完都检查结果。CASE WHEN 分支逻辑数据分析常需分类。比如“订单金额1000为‘大单’500-1000为‘中单’否则‘小单’”。这比在Excel里用IF函数直观多了。写一个查询SELECT order_id, total_amount, CASE WHEN total_amount 1000 THEN 大单 WHEN total_amount 500 THEN 中单 ELSE 小单 END AS level FROM orders;6.3 防踩坑我第一次学时最该早知道的3个习惯永远先写注释再写SQL在敲任何一行代码前先用--写一句中文说明比如-- 目标查每个类别的商品数再写SELECT category_id, COUNT(*) FROM products GROUP BY category_id;。这能强迫你理清思路避免写着写着忘了初衷。WHERE条件宁可拆开不要堆一起与其写WHERE status paid AND amount 100 AND DATE(created_at) 2023-10-01不如分行写每行一个条件。调试时可以逐行注释掉快速定位问题。每次执行前先问自己“这个查询会返回多少行”如果表有10万行而你没加WHERESELECT * FROM big_table会卡死。养成预估的习惯是专业和业余的分水岭。从那以后我每次写完一个复杂查询都强制走一遍“注释→预估行数→执行→验证结果是否符合注释”的闭环。哪怕多花30秒也比花30分钟排查一个拼写错误强。希望帮到你。本文还有配套的精品资源点击获取