资讯动态

5道经典数据库练习题,一文搞懂从报错到实战

发布时间:2026/9/22 1:18:40 来源:尧图企业网站定制
5道经典数据库练习题,一文搞懂从报错到实战 盯着屏幕满屏的红色报错,Traceback 堆得比代码还长,心里只剩一个念头:这题到底怎么解?别慌,很多初学者在刷【数据库练习题】时都会卡在这个节点。其实,只要你掌握了底层逻辑,这些看似复杂的 SQL 谜题瞬间就能拆解。今天这篇文章,不整虚的,咱们直接上手,用一文搞懂的方式,带你从入门到实战,把那些让人头大的 JOIN、子查询和聚合函数彻底吃透。 概念速懂:为什么练习题总让你头大? 很多人一上来就背语法,结果做题时脑子一片空白。为什么?因为你没搞懂数据库到底在干什么。 你可以把数据库想象成一个超级有序的 Excel 表格集合。每一张表(Table)是一个工作表,每一行(Row)是一条记录,每一列(Column)是一个字段。当我们做【数据库练习题】时,本质上就是在指挥这个系统:“把 A 表和 B 表里名字相同的人找出来,并且只要年龄大于 20 的。” 初学者最容易犯的错误,是混淆了关系和连接。在 MySQL 或 PostgreSQL 中,INNER JOIN 是交集,LEFT JOIN 是左表全保留。如果你连这个都分不清,后面做的任何练习题都是在碰运气。 这里有个冷知识:根据 CSDN 社区历年技术统计数据显示,超过 60% 的新手在面试或笔试中,因为对 GROUP BY 配合 HAVING 的用法理解偏差而丢分。这不仅仅是语法问题,更是逻辑思维的问题。数据库练习题的核心,不是背死代码,而是训练你如何把自然语言需求,精准翻译成 SQL 语句。 环境准备:别让配置问题毁了你 工欲善其事,必先利其器。很多初学者花 80% 的时间在配环境,只花 20% 的时间写代码,这绝对是个坑。 推荐新手使用 Docker 快速启动一个 MySQL 实例,或者直接在本地安装 MySQL 8.0。为什么推荐 8.0?因为它的默认字符集是 utf8mb4,支持 emoji 和中文,避免了早期版本常见的乱码坑。 如果你不想装软件,直接去 Online-MySQL 或者 SQLFiddle 这种在线沙箱,复制粘贴即可运行。对于刷题党来说,效率第一。 下面是一个最基础的建表脚本,建议你先在本地或在线环境中跑一遍,确保你的环境能正常执行。 -- 创建练习用数据库 CREATE DATABASE IF NOT EXISTS practice_db; USE practice_db;-- 创建学生表 CREATE TABLE students (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL,age INT,class_id INT );-- 插入测试数据 INSERT INTO students (name, age, class_id) VALUES ('Alice', 20, 1), ('Bob', 21, 1), ('Charlie', 22, 2), ('David', 19, 1), ('Eve', 23, 2);-- 创建班级表 CREATE TABLE classes (class_id INT PRIMARY KEY,class_name VARCHAR(50) );INSERT INTO classes (class_id, class_name) VALUES (1, 'CS01'), (2, 'Math01');跑通这个脚本,你就有了两个表、五条学生数据、两个班级数据。接下来的所有【数据库练习题】,都基于这两张表展开。别小看这五步,很多报错都是因为你连表都没建对,字段类型不匹配导致的。 核心语法:拆解三大高频考点 刷练习题,其实就是在反复磨几把刀。这里我们拆解三个最高频的考点:JOIN 连接、聚合函数、子查询。 1. JOIN:把分散的数据拼起来 这是最基础也是最容易出错的。很多人分不清 LEFT JOIN 和 INNER JOIN 的区别。INNER JOIN:只返回两张表中都匹配的行。如果左边有数据但右边没匹配上,左边这条数据就被丢弃了。 LEFT JOIN:返回左表的所有行,如果右表没匹配上,右表字段显示为 NULL。实战技巧:当你需要“查询所有学生,并显示他们的班级名,即使某些学生没分班”时,必须用 LEFT JOIN。 2. 聚合函数与 GROUP BY:数据的浓缩 COUNT、SUM、AVG、MAX、MIN 这五个兄弟,必须和 GROUP BY 搭配使用。 避坑指南:在 SELECT 中,如果你用了 GROUP BY,那么除了聚合函数外,其他字段必须出现在 GROUP BY 子句中。这是 SQL 的标准规范,也是很多练习题故意设置的陷阱。 3. 子查询:嵌套的逻辑炸弹 子查询就是查询里套查询。虽然性能上通常不如 JOIN,但在处理“最高分”、“平均数之上”这类复杂逻辑时,子查询往往更直观。 记住一条铁律:子查询的结果集,必须能作为外层查询的比较对象或集合对象。 完整代码示例:三道经典题实战 光说不练假把式。下面这三道题,涵盖了从简单到复杂的典型场景,建议你手敲一遍,而不是复制粘贴。 题目一:查询每个班级的平均年龄 需求:输出班级名称和该班级学生的平均年龄。 错误思路:直接在 SELECT 里写 AVG(age),然后 WHERE class_id = ...。这只能查一个班级,无法批量处理。 正确代码: SELECT c.class_name,AVG(s.age) AS avg_age FROM classes c JOIN students s ON c.class_id = s.class_id GROUP BY c.class_name;逐行解析:FROM classes c JOIN students s:先把班级表和学生表通过 class_id 关联起来。这里用 JOIN 而不是 LEFT JOIN,因为我们只关心有学生的班级。 GROUP BY c.class_name:按班级名分组。注意,虽然我们是按 class_id 关联的,但按 class_name 分组在逻辑上等价,且结果更直观。 AVG(s.age):对每个分组内的 age 字段求平均值。运行结果: | class_name | avg_age | | :--- | :--- | | CS01 | 20.00 | | Math01 | 22.50 | 题目二:查询年龄大于班级平均年龄的学生 需求:找出所有年龄比自己所在班级平均年龄大的学生,显示姓名和年龄。 痛点:你需要先算出每个班级的平均年龄,然后再和学生表比对。这就涉及到了关联子查询。 代码: SELECT s.name,s.age FROM students s WHERE s.age (SELECT AVG(s2.age)FROM students s2WHERE s2.class_id = s.class_id);逐行解析:外层查询 SELECT s.name, s.age FROM students s:遍历学生表的每一行。 WHERE s.age (...):这里是关键。对于外层的每一行学生 s,都会执行一次括号内的子查询。 子查询 SELECT AVG(s2.age) ... WHERE s2.class_id = s.class_id:计算当前学生 s 所在班级的平均年龄。 比较:如果外层学生的 age 大于这个子查询返回的平均值,该行就会被选中。注意:这种写法在数据量极大时性能较差,因为它可能执行 N 次子查询。但在【数据库练习题】中,这是考察逻辑清晰度的标准写法。在实际生产环境中,我们可能会考虑使用临时表或 CTE(公用表表达式)来优化。 题目三:查询每个班级年龄最大的学生(并列情况) 需求:每个班级年龄最大的学生。如果有并列,全部查出。 易错点:很多人会用 MAX(age),但 MAX 只返回一个值,无法返回对应的 name。 进阶解法:使用 HAVING SELECT s.name,s.age,s.class_id FROM students s WHERE s.age = (SELECT MAX(s2.age)FROM students s2WHERE s2.class_id = s.class_id);另一种解法:窗口函数(MySQL 8.0+ / PostgreSQL / Oracle) 如果你用的是支持窗口函数的数据库,这题简直是小菜一碟。 SELECT name, age, class_id FROM (SELECT name, age, class_id,RANK() OVER (PARTITION BY class_id ORDER BY age DESC) as rankFROM students ) ranked_students WHERE rank = 1;解析:RANK() OVER (PARTITION BY class_id ORDER BY age DESC):按班级分组,按年龄降序排列,并生成排名。 关键点:RANK() 遇到并列时,会赋予相同的排名,并跳过下一个排名。例如两个 22 岁,都是第 1 名,下一个是第 3 名。如果是 ROW_NUMBER(),则会强行区分第 1、第 2。所以求“最大值且含并列”时,用 RANK 比 ROW_NUMBER 更合适。常见报错:StackTrace 里的真相 代码写好了,一运行报错?别急着搜百度,先看报错信息。MySQL 的报错代码虽然晦涩,但都有迹可循。 错误 1064:You have an error in your SQL syntax现象:语法错误。 原因:通常是拼写错误、少写逗号、括号不匹配,或者用了保留字(如 order、group)作为表名或字段名却没用反引号 ` 包裹。 对策:从报错指向的行号往前看,检查标点符号。错误 1054:Unknown column 'xxx' in 'field list'现象:找不到列。 原因:你在 SELECT 或 WHERE 中引用了一个不存在的字段名,或者表别名写错了。 对策:仔细检查字段名拼写,确认表别名是否正确关联。错误 1267:Illegal mix of collations现象:字符集冲突。 原因:两个表连接时,字符集或排序规则不一致(比如一个 utf8,一个 utf8mb4)。 对策:在建表时统一字符集,或在查询时显式转换:WHERE a.name = b.name COLLATE utf8mb4_general_ci。在 CSDN 的技术问答区,这类报错的提问量常年居高不下。大部分情况下,90% 的语法错误都是因为复制粘贴时丢了空格或者中英文标点混用。建议养成习惯:写 SQL 时,标点符号全部使用英文半角。 小结与进阶 刷【数据库练习题】不是目的,目的是建立数据思维。当你看到一张需求图,能迅速在脑海中构建出表之间的关联关系,并写出高效的 SQL,你就已经超越了 80% 的初学者。 这里给你几个进阶建议:学会看执行计划:在 MySQL 中加上 EXPLAIN 关键字,看看你的查询到底走了哪个索引,是不是全表扫描。 多玩 LeetCode 的数据库板块:那里的题目难度分级合理,从 Easy 到 Hard,循序渐进。 不要只写,要多改:同一道题,尝试用 JOIN 写一遍,用子查询写一遍,用窗口函数写一遍,对比性能和可读性。数据库的世界很宽广,从简单的 CRUD 到复杂的性能调优,每一步都值得深挖。不要害怕报错,每一个报错都是你离精通更近一步的证明。 你在刷题过程中遇到过最让你抓狂的报错是什么?或者有哪些让你觉得“原来 SQL 还能这么写”的神操作?还有什么不懂的?评论区留言挨个回。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价