简介面向SQL初学者和需要巩固MySQL查询能力的开发者这套练习围绕单表与多表查询展开共有八套题目其中单表四套、多表四套。题目由浅入深先练习字段选取、条件过滤、排序和分组聚合再通过内连接、左连接、右连接及子查询等常见写法理解多张表之间的关联与数据整合方法。资源包共十九个文件主要包含文本文件、SQL脚本和压缩包三种形式文本文件用于分套展示题目与答案要点SQL脚本提供建表语句、示例数据和查询练习压缩包则汇总了完整的练习含答案目录整体约二十二KB内容紧凑导入MySQL环境即可开始操作。目前已有九百一十一人学习下载无论是准备考试、面试刷题还是日常提升查询效率都值得对照练习。题目难度层次清楚还附带答案压缩包便于自查薄弱环节帮助读者把SQL语法真正转化为熟练的实战能力。 准备SQL练习题先想清楚一个问题为什么练了那么多套题一上考场还是发懵很多人在学SQL的时候刷题量并不少单表查完查多表多表查完查子查询但遇到真实需求仍然不知道从哪下手。我见过不少类似的困境语法都认识看到题也知道大概要做什么但一到手写要么忘了GROUP BY和HAVING的配合逻辑要么两张表一JOIN就出来一大堆重复数据。问题多半出在练习的时候只关注“把答案写出来”没有拆解每一道题背后的知识点和考察意图。这套《单表多表各四套》SQL练习题就是冲着这个问题来的。整体设计很简单前四套聚焦单表操作把SELECT、WHERE、ORDER BY、聚合、分组、去重这些基础点打到滚瓜烂熟后四套切到多表连接从最简单的INNER JOIN一路做到自连接、子查询和聚合连查。适合正在学SQL的初学者、准备数据库相关面试的求职者也适合那些学完语法但做题没思路的同学作为复盘材料。为了方便描述下面所有题目都基于一个统一的图书管理库库里有读者表、图书表、出版社表、借阅记录表。表格数据我自己造的你在本地练习的时候也建议自己造一份类似的数据别直接用网上的现成库——自己把INSERT语句写一遍对字段类型和关联关系的理解会比单纯查题深得多。1. 题目设计的底层逻辑为什么分单表和多表各四套1.1 单表练的是“条件构造能力”单表查询的核心不是背语法而是把自然语言翻译成WHERE条件的准确性。很多人写SQL慢不是不知道SELECT怎么写而是不知道“去年出版的书”应该翻译成YEAR(publish_date) 2023还是publish_date 2023-01-01 AND publish_date 2024-01-01。四套单表题就是从简到繁第一套只要求按条件筛选并排序第二套开始加聚合函数第三套进入分组和HAVING过滤第四套把去重、CASE WHEN、日期函数、分页这些常用但容易忘的语法揉在一起。这样安排是为了让练习者在一个可控的复杂度范围内逐步建立“看到需求-拆解条件-选择语法”的反射路径。1.2 多表练的是“关联关系的拆解”多表查询的难点不在JOIN语法本身而在于搞清楚表与表之间是怎么关联的。很多初学者写多表查询上来就JOIN结果数据多了20倍因为漏了关联条件或者关联字段选错了。后面四套多表题尽量覆盖到实际场景中常见的几种关系类型一对一补全信息、一对多导致的重复行、多对多需要中间表、同一张表内上下级关系的自连接。每套题都刻意控制表的数量和JOIN的类型第一套只做两张表的基础连接第三套才上三表关联避免一上来就被复杂的表关系绕晕。2. 单表四套从基础筛选到综合进阶2.1 第一套基础查询与排序题目列表查询读者表中所有女性的姓名、电话和注册日期。查询图书表中价格大于50元的书名和价格并按价格从高到低排序。查询出版社表中成立时间在2000年之后的出版社名称。查询图书表中书名包含“SQL”的图书信息。查询图书表中价格在50到100元之间的图书按价格升序排列。这套题没有任何弯弯绕考察的就是SELECT、FROM、WHERE、ORDER BY四个基础子句的组合。第3题考察日期比较第4题考察LIKE匹配第5题考察BETWEEN的写法。注意BETWEEN是包含边界的闭区间BETWEEN 50 AND 100等同于price 50 AND price 100。如果你不确定边界行为建议写完之后用EXPLAIN看看条件转换或者直接用运算符号写避免边界混乱。第1题很多人会写成WHERE 性别 女但真实表结构里字段名往往是拼音或者英文缩写比如gender或者sex。拿到题目第一步绝对不是写SQL而是先确认字段名这是实际开发中最重要的习惯。2.2 第二套聚合函数与数值计算题目列表统计图书表中图书总数和总价格。查询最贵图书的价格和书名。统计出版社表中出版社的平均成立年份。查询图书表中价格大于平均价格的图书书名和价格。统计每位作者的图书数量结果按数量降序排列。第1题考察COUNT和SUM的组合第2题考察MAX第3题考察AVG第4题是个小坑——很多人会先查出平均价格再把平均值手写在第二个查询里。这种方式在练习时可以但在实际项目中不建议因为平均值每次都可能变化正确做法是用子查询或窗口函数这个后面多表部分会展开。第5题提前引入了GROUP BY但没有加HAVING就是为了让练习者先把“分组-聚合”这个整体结构印在脑子里再去理解分组后的过滤。写聚合相关的SQL时我最常提醒别人的一点是COUNT(*)和COUNT(列名)不一样。COUNT(*)统计所有行COUNT(字段)统计该字段非NULL的行数。如果字段有NULL值两个结果会不一样。2.3 第三套分组统计与HAVING过滤题目列表按出版社统计图书数量只看数量大于3的出版社。查询每个出版年份的图书平均价格筛选平均价格大于60元的年份。按作者统计图书总价格筛选总价格最高的前三位作者。统计不同价格区间50以下、50-100、100以上的图书数量。第1、2题核心是GROUP BY HAVING的组合。第2题这种“先聚合再过滤”的需求很多人会下意识用WHERE结果报错或者结果不对。记住一条原则WHERE是行级过滤在分组之前执行HAVING是分组级过滤在分组之后执行。你要过滤的是聚合结果就必须用HAVING。第3题考察LIMIT和ORDER BY配合这个在求职笔试中出现频率极高属于送分题但也最容易被扣分——因为有人忘了DESC。第4题是CASE WHEN和GROUP BY结合也是实际统计报表里常见的写法。思路是把价格映射成“档位标签”再按标签分组计数。2.4 第四套去重、日期函数与CASE WHEN题目列表查询所有不同的出版社ID。查询注册满一年的读者数量。统计每种图书状态在馆/借出/下架的数量状态字段用数字存储1在馆2借出3下架。查询2023年借出次数最多的前5本图书。第1题是DISTINCT的典型用法但很多人不知道DISTINCT可以作用于多个字段的组合比如SELECT DISTINCT publisher_id, category_id这是后续做商品类目分析时常用的技巧。第2题日期计算不同数据库写法不同。MySQL可以用DATE_SUB和DATEDIFFSQL Server用DATEADD和DATEDIFF这提醒我们SQL语法大方向一致但日期函数几乎是每种数据库差异最大的部分。面试时遇到日期题先确认对方用的是哪种数据库。第3题和第4题都是CASE WHEN的实际应用。第4题相对难一点除了CASE WHEN还要求先按借书表分组算出每本书在2023年被借出的次数再排序取前五。这里有个隐藏考察点借出时间字段是日期类型还是字符串类型如果存的是字符串就需要先做类型转换或格式匹配。3. 多表四套从两表JOIN到子查询实战3.1 第一套INNER JOIN两表连接基础题目列表查询所有在借图书的书名、读者姓名和借出日期。查询每位读者当前借阅的图书数量。查询图书表中每本书对应的出版社名称。第1题是两表JOIN最标准的应用借阅记录表通过book_id关联图书表再通过reader_id关联读者表。由于这是“一个读者借了多本书一本书可以被多次借阅”的关系结果里会出现同一个读者对应多行记录这是正常的。第2题考察JOIN和GROUP BY连用。注意这里必须先JOIN再分组有些人会先写在子查询里查借阅记录表再去关联读者表一种也能做出来但写法混乱得多。通用原则尽量让JOIN发生在简化之前除非性能问题严重否则先保证逻辑清晰。第3题是纯补全信息1对1关系最简单但也是练习JOIN语法的必要步骤。3.2 第二套LEFT JOIN与NULL的陷阱题目列表查询所有图书及其借出次数没被借过的也要显示。查询所有读者中从未借过书的人。查询每个出版社当前被借出的图书数量没有借出记录的出版社显示0。第1题和第3题都要求“没记录也要显示”这就是LEFT JOIN存在的意义。很多人会用子查询NOT IN但NOT IN遇到NULL会有个严重问题如果子查询结果集中含有NULL值NOT IN会整体返回空集。用LEFT JOIN IS NULL则完全不会踩这个坑。第2题是第1题的逆操作筛选出LEFT JOIN之后右表字段为NULL的行就是“从没借过书”的读者。第3题有个小难点统计的是“被借出”的数量要在LEFT JOIN连接时加上状态过滤条件。这时候过滤条件放在ON后面和放在WHERE后面结果会不同。放在ON里不匹配的行仍然保留只是右表字段为NULL放在WHERE里不匹配的行就被过滤掉了。这个是初学者最容易犯的错。注意LEFT JOIN时对右表字段的过滤条件要么在ON里带上要么允许NULL存在后在WHERE里做IS NULL判断千万不要直接写WHERE 右表字段 某个值否则LEFT JOIN会退化成INNER JOIN的效果。3.3 第三套三表关联与中间表题目列表查询每本书的作者姓名、出版社名称和价格。查询被借出次数超过10次的书名及其当前状态。查询每个读者借阅过的图书分类结果去重。查询借出记录中存在但图书表中不存在对应记录的book_id孤儿数据。第1题是两表JOIN的延伸图书表同时关联作者表和出版社表要注意JOIN的顺序。先确认主表再逐个关联从表逻辑上不容易乱。第2题需要图书表、借阅记录表二次关联第一次先统计每本书的借出次数第二次再关联图书表取书名。如果不想写子查询可以先建一个临时统计视图再做JOIN都可行但考试时建议用子查询省事。第3题是多对多关系拆解一个读者可以借多本书一本书属于一个分类要通过借阅记录表这个中间表把读者和分类关联起来最后用DISTINCT去重。第4题比较有意思专门考察逆向思维。通常大家只关心怎么JOIN出有效数据很少考虑怎么找出关联失败的数据。用LEFT JOIN IS NULL的逻辑查图书表中没有匹配记录的book_id其实就是找借阅记录表里的脏数据。3.4 第四套自连接、子查询与聚合连查题目列表查询借阅次数高于平均借阅次数的读者姓名。查询每个出版社价格最高的图书信息。查询分数线找出所有价格高于“数据库”类图书平均价格的图书。查询每位读者第一次借书的日期用窗口函数实现。查询互相借过同一本书的读者对。第1题是个综合题不止JOIN还要求子查询算出全体读者的平均借阅次数再JOIN读者表和借阅记录表查询每人借阅次数最后做比较。少一步都不行。第2题是“取每个分组中某字段最大的整行数据”这类问题在面试中出现频率极高。解法有子查询关联、窗口函数ROW_NUMBER()等。建议两种都写一遍才能真正理解它们在逻辑上的差别。第3题是在JOIN的基础上叠加子查询实际上限定了“图书表中分类为数据库的书”这一个子集再对这个子集求平均值最后用它过滤所有图书。第4题如果接触过SQL Server或PostgreSQL窗口函数几乎是标准解法。ROW_NUMBER() OVER(PARTITION BY reader_id ORDER BY borrow_date)然后取序号为1的行就能得到每位读者的第一次借书日期。MySQL 8.0以上也支持这个写法。第5题是自连接题目也是整个八套题里综合性最强的需要借阅记录表自己关联自己查到同一本书被不同读者借过再排除和自己配对的情况最后用不等号去重保证(A, B)和(B, A)不重复出现。这道题能完整写出来的话多表查询的基础算是真的扎实了。4. 常见错误与排查技巧实录4.1 字段名错误和列名歧义多表查询最常见的报错永远是列名不明确。两张表都有id字段时直接写WHERE id 1大概率是错的。实际工作中我见过无数次这种低级错误导致的线上故障排查半天最后发现是多加了前缀。排查方式很简单报错信息里提示ambiguous时就在所有SELECT字段前加上表别名前缀。建议一开始写多表查询就给每个表起简短的别名养成习惯后能省很多事。4.2 JOIN条件写错导致数据膨胀很多初学者写JOIN只管ON里的等值条件没注意到一张表存在多条匹配记录时结果集会膨胀。比如把图书表和借阅记录表JOIN一本书被借了5次就会出现5行。如果再继续JOIN第三张表就是5乘以第三张表的匹配数数据量暴增。排查思路是先单独对每个JOIN做COUNT计数确认行数增量是否符合预期再继续往后面叠条件。检查顺序能帮你快速定位是在哪一次JOIN出的问题。4.3 GROUP BY与SELECT字段不匹配关于GROUP BYMySQL有一个既方便又坑人的特性默认开着ONLY_FULL_GROUP_BY时SELECT中出现的非聚合字段必须全部出现在GROUP BY里。有的环境允许不匹配但这会带来不确定的取值。不同数据库的处理方式也不同SQL Server和PostgreSQL直接报错MySQL开元时允许Oracle对于完全不需要分组字段的查询没这个问题。尽量把所有非聚合字段都写进GROUP BY既能兼容所有数据库也能避免隐性问题。4.4 日期过滤的边界问题日期字符串比较时book_date 2024-01-01不会包含2024年1月1日当天0点整的记录全部按0点0分0秒处理。如果你想包含整个1月份的记录BETWEEN 2024-01-01 AND 2024-01-31也查不到1月31日23点59分的记录因为上限到1月31日0点就截断了。建议对时间字段用半开区间date 2024-01-01 AND date 2024-02-01这是最标准的写法也最容易被搜索引擎优化和面试官接受。4.5 无法利用索引导致查询慢练习题大多数表数据量小执行计划差异看不出来但真实项目一旦数据量过千万一个没走索引的JOIN就可能卡死。慢SQL排查时第一件事不是改SQL而是看执行计划是否出现全表扫描。即便是做SQL练习也建议偶尔用EXPLAIN看看自己的查询有没有走索引对后续调优帮助很大。5. 练习题使用建议与实际心得既然有八套题肯定猜你是想自己练或者用来备考。我的经验是不要一次性全刷完拆成三天更有效。第一天做单表第一、二套重点巩固基础查询和聚合语法。第二天做单表第三、四套重点掌握分组、HAVING、CASE WHEN。第三天做多表四套每做完一套把涉及的表关联关系画出来。画表关联关系是有用的习惯哪怕只是在纸上画框标明主键外键也能帮助理清连接条件。最后再分享一个我自己的做题心得。看答案解析时不要只满足于“这题我会了”而是试着给自己提三个问题这个语句用到的命令在什么样的场景下会失效如果数据量扩大一百倍它还能跑吗有没有另一种等价的写法每道题都问自己一遍这八套题刷完应付大多数入门的SQL笔试和日常工作绝对够用了。本文还有配套的精品资源点击获取