尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
MySQL SQL 100道基础练习题:从语法到思维的实战训练
说点实在的我现在能随手写出各种复杂的关联查询跟当年老老实实刷完那套“MySQL SQL100道基础练习题”有很大关系。这东西不是什么高深秘籍就是一百道覆盖了从最简单的SELECT到窗口函数、行列转换的题目。但它的好处在于结构设计得比较科学每几道题就引入一个新知识点再在后面的题里反复用让你不知不觉把SQL的基础功扎稳。我后来带过几个新人也用这套题做入职摸底和训练效果比直接扔官方文档强太多。这套题适合谁想转数据岗位的、刚入职的后端开发、需要自己取数的业务分析师都合适。它解决的是大多数人“语法看得懂、写不出正确SQL”的尴尬——你哪怕背熟了所有关键字没有足够的场景训练到了真实业务里照样抓瞎。接下来我把这套题的知识点分布、刷题方法、高频考点以及我在刷题过程中踩过的坑都整理出来。1. 为什么我推荐用这100道题练手1.1 它练的不只是语法更是SQL思维很多人有个误区觉得SQL是“背下来就会”的语言。实际上SQL更像是一种用集合思维描述问题的工具。你写SELECT的时候脑子里要想的不是“一行一行怎么处理”而是“我需要对整个数据集做什么操作”。这套100题最大的价值就是通过大量重复场景帮你建立这种集合思维。举个例子刚刷到GROUP BY相关题目时我习惯性地想“我要把几行合并成一行”结果总是漏掉聚合列的处理。后来刷多了才发现正确思路是先想“我要按什么维度分组分组后对每组做什么计算”再落笔写SQL。这种思维转换只靠看文档是体会不到的必须通过题目来磨。我还注意到一个细节这套题里面有很多题目之间是递进关系。比如先练一张表内的统计再练两张表的JOIN统计最后过渡到三张表以上。这种设计比随机出题的平台好很多因为SQL的难点本来就在于“多表关联时的逻辑清晰度”而不是单个语法点的难度。1.2 从“会写”到“写对”的跨越刷题之前我以为自己“会写SQL”能查数据、能排序、能连接。但真正做这套题的时候前面三十题就把我打回原形。题目很简单比如“查找重复数据”“按部门统计人数”但执行完发现结果跟预期不一样或者报了个没见过的错误。问题出在哪大多是边界情况考虑不周。比如NULL参与运算的结果是NULL、COUNT(列)会跳过NULL、LEFT JOIN的关联条件放错位置、字符串比较时的大小写规则。这些细节在教科书上就是一行字但你亲自写错一次、排查一次后才会一辈子记住。所以我把这套题定位成“正确性训练工具”。它的目的不是让你学会冷门语法而是让你在常见场景下能一次写对。这个能力在面试里很占便宜在工作里更重要——线上数据库可没法让你反复试错。2. 知识点地图100题到底覆盖了什么2.1 前30题单表查询的基本功这套题的前面部分基本围绕一张表展开。重点包括WHERE条件的各种过滤比较运算、逻辑运算、IN和NOT IN、BETWEEN AND排序与分页ORDER BY配合ASC/DESC、LIMIT的偏移量计算去重DISTINCT的用法和陷阱模糊匹配LIKE配合通配符%下划线_的匹配规则别名与表达式SELECT里用别名、CASE WHEN做条件判断这些单表操作看着基础实际工作中80%的日常取数都落在里面。我刷这部分时养成的一个习惯是每写一条WHERE都会问自己“NULL会不会影响这个条件”。比如WHERE name ! 张三如果name列里有NULL那这些行不会被查出来。原因很简单NULL与任何值比较的结果都是UNKNOWN而WHERE只保留条件为TRUE的行。这个知识点我当年就是在一道“找出所有非某部门员工”的题里栽了跟头才彻底明白的。2.2 中段30题JOIN与聚合的组合拳第30题到60题是这套题的核心精华区。这一阶段开始引入多张表主要练四类东西JOIN的各种类型INNER JOIN、LEFT JOIN、RIGHT JOIN、CROSS JOIN聚合函数COUNT、SUM、AVG、MAX、MINGROUP BY分组与HAVING过滤多表关联下的聚合统计比如“每个客户的订单总额”“各分类的商品数量”这里有三个高频易错点第一ON和WHERE的区别。LEFT JOIN时如果你在ON子句里对右表加条件比如ON a.id b.id AND b.status 1那它过滤的其实是关联条件的一部分保留所有左表行。但如果你把这条件放到WHERE里就相当于先JOIN完再过滤结果可能只剩满足条件的行。这个区别在真实业务里极其重要我见过不止一次线上报表数据对不上最后查下来就是这里写错了。第二GROUP BY与SELECT列的对应关系。MySQL在默认SQL_MODE下开启ONLY_FULL_GROUP_BYSELECT后面出现的非聚合列必须全部出现在GROUP BY中。比如SELECT department, gender, COUNT(*) FROM employee GROUP BY department这句话在5.7以上版本直接报错因为gender没被分组。解决方法是把gender也加到GROUP BY里或者用聚合函数包住它比如MAX(gender)。第三HAVING和WHERE的分工。WHERE是在分组前过滤原始行HAVING是在分组后过滤分组。一个典型例子查订单数量超过5个的客户你必须在GROUP BY customer_id之后用HAVING COUNT(*) 5而不能用WHERE。如果把条件写在WHERE里SQL会直接报错因为此时COUNT(*)还没有被计算出来。2.3 后40题子查询、窗口函数与综合场景后半部分难度明显上升开始出现子查询、EXISTS、IN以及窗口函数。这套题在基础题库里引入窗口函数我觉得是很良心的设计。因为MySQL 8.0普及之后ROW_NUMBER()、RANK()、DENSE_RANK()已经成了分组排名、取Top N的标配写法而很多旧式教程还停留在用自连接实现的黑暗时代。这一阶段要练的核心场景包括子查询做过滤WHERE salary (SELECT AVG(salary) FROM emp)EXISTS与IN的选择与区别窗口函数ROW_NUMBER()、RANK()、DENSE_RANK()、SUM() OVER()分组成员函数PARTITION BY的用法简单的行列转换、日期处理、字符串函数组合刷到这一阶段我才认真理解了“窗口函数和GROUP BY的区别”GROUP BY会把多行合并成一行窗口函数不会减少行数它只是为每一行计算一个基于窗口范围的附加结果。比如同时展示每个员工自己的工资和部门的平均工资就必须用AVG(salary) OVER(PARTITION BY department)来实现GROUP BY做不到这一点。2.4 一张表看懂难度分布题目范围核心考点难点常见错误1-30单表查询、排序、过滤LIKE模糊匹配、NULL处理忘记处理空值31-60JOIN、聚合、分组ON与WHERE混淆关联条件写错位置61-80子查询、EXISTS子查询性能陷阱误用IN导致结果异常81-100窗口函数、综合应用分组内排名、行列转换不理解PARTITION BY我当时刷完这张表之后又把它当成复习目录每过一个周末就照着考点自己复现一遍。这个习惯帮我撑过了好几次面试的手写SQL环节因为大部分面试题其实就是这套题里某几道的变体。3. 刷题实操环境搭建与高效方法3.1 本地环境怎么搭我推荐用Docker直接起一个MySQL 8.0环境干净、可控、重置方便。如果你机器上还没装Docker也可以直接用本机安装的MySQL Server或者MariaDB但有个建议不要用MySQL 5.6及以下版本。这些老版本不支持窗口函数刷到最后你会卡在排名题上还得去装新版本白白浪费时间。我日常使用的启动命令很简单docker run --name mysql-study -e MYSQL_ROOT_PASSWORDroot -p 3306:3306 -d mysql:8.0启动之后用客户端连接mysql -h127.0.0.1 -uroot -proot然后建议手动把建库和建表的SQL敲一遍。有些题目会提供现成的初始化脚本但我刻意不直接用。敲建表语句的过程能让你对每张表的字段类型、主键、外键关系有个初步印象后面写查询时就不用来回翻表结构。数据量不大敲一遍也就几分钟。3.2 一份高效的刷题流程我自己总结了一套刷题流程用下来觉得效率很高分享给你看题后先不执行在编辑器里把SQL完整写出来自己模拟执行一遍预测一下结果集应该长什么样执行SQL和预测结果对比不一致就逐行排查查看官方参考解法对比自己和参考答案的差异把有价值的易错点记录到个人错题本里这套流程的关键是把“动手查”放在“动脑想”之后。很多新手习惯拿到题就执行发现报错再修这样也能过题但思维能力提升很慢。SQL是声明式语言你不能像写Java那样一步步调试只能靠脑内模拟数据流。练得多了你对“这一条SQL会先过滤哪些行、再按什么分组”会产生直觉这对处理复杂业务查询帮助特别大。3.3 为什么我强烈建议做错题本刷到中期我开始对重复犯的错做统计发现几乎都集中在三类NULL处理、JOIN条件位置、分组列匹配。于是我在本地建了一个简单的错题表学号当主键记录题目编号、错误SQL、错误原因、正确写法。用数据库来记数据库的错题也算是有点行为艺术但效果出奇好。为什么推荐错题本因为刷题最大的问题不是“不会做”而是“错过的还会再错”。尤其是那些不报错但结果错的题目比如LEFT JOIN后数据变多、去重后丢数据如果你不复盘下次遇到类似场景还是会踩。错题本能让你把零散的“踩坑体验”结构化形成自己的SQL知识体系。4. 三组必刷题的完整拆解4.1 分组Top N窗口函数的标准写法这套题里有一道非常经典的问题查询每个部门工资最高的员工。新手最常见的错误解法是这么写的SELECT department, employee_name, MAX(salary) FROM employee GROUP BY department;这个写法有两个问题。第一在ONLY_FULL_GROUP_BY开启时直接报错第二即使在某些宽松模式下能执行返回的employee_name也不一定是工资最高的那个员工而是一个随机值。这种SQL在业务里就是定时炸弹。正确的做法是用窗口函数SELECT department, employee_name, salary FROM ( SELECT department, employee_name, salary, ROW_NUMBER() OVER(PARTITION BY department ORDER BY salary DESC) AS rn FROM employee ) t WHERE rn 1;这里的关键是先用ROW_NUMBER()给每个部门内按工资降序编号然后外层过滤出每个部门的第一名。如果你希望并列第一也都能查出来就把ROW_NUMBER()换成DENSE_RANK()或RANK()。这三者的区别也是高频面试题RANK()遇到并列会跳过排名比如两个人并列第一下一个人是第三名DENSE_RANK()不跳下一个人是第二名ROW_NUMBER()则强制给并列的人随便分个先后。我刷这道题的时候还特意对比了传统自连接写法比如SELECT a.department, a.employee_name, a.salary FROM employee a LEFT JOIN employee b ON a.department b.department AND a.salary b.salary WHERE b.employee_id IS NULL;这个写法确实能得到结果但逻辑不好理解而且数据量大时性能通常比窗口函数差。MySQL 8.0之后我建议你直接放弃自连接方案专练窗口函数。4.2 重复数据查找与删除自连接的经典场景另一道让我印象深刻的题是某张表里email字段存在重复值要求先找出重复的email再删除多余的记录只保留一条。查找重复的SQL很简单SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) 1;删除只保留一条的SQL很多新人会直接写DELETE FROM users WHERE id NOT IN ( SELECT MIN(id) FROM users GROUP BY email );这句在MySQL里会报错You cant specify target table users for update in FROM clause原因是MySQL不允许在同一张表上一边查询一边修改。解决思路是给子查询套一层别名表让MySQL认为它是独立的结果集DELETE FROM users WHERE id NOT IN ( SELECT * FROM ( SELECT MIN(id) FROM users GROUP BY email ) t );注意我在子查询的外面又包了一层SELECT * FROM这就是网上常说的“派生表临时表”技巧。刷这道题给我的收获是很多MySQL报错不是概念问题而是语法层面的限制记住这个套路的应用场景以后遇到同款报错就能秒解。4.3 行列转换CASE WHEN加聚合的拼接行列转换是很多人觉得“难”但实际很套路的题。题目通常长这样有一张订单明细表包含年份、月份、产品类型、销售额要求按月份为行、产品类型为列统计每个月的销售额。典型的静态列转换写法是SELECT month, SUM(CASE WHEN product_type A THEN amount ELSE 0 END) AS sales_a, SUM(CASE WHEN product_type B THEN amount ELSE 0 END) AS sales_b, SUM(CASE WHEN product_type C THEN amount ELSE 0 END) AS sales_c FROM orders GROUP BY month;这个写法的灵魂在于CASE WHEN把某一行中特定类别的数据转换成一个新的列再用聚合函数合并。你可以把它理解成“先造列再分组”。网上还会有动态行列转换用存储过程或者分组拼接的方式生成列名但那属于进阶技巧。基础100题里练到静态版本就够了关键是要理解两个点一是CASE WHEN必须放在聚合函数内部否则分组后无法正确合并二是ELSE 0和ELSE NULL在执行效果上不一样用SUM时两者结果一致但逻辑语义不同。5. 刷题现场踩过的坑和排查记录5.1 分组查询报错ONLY_FULL_GROUP_BY这是这套题里遇到最多的报错特征很明确执行带GROUP BY的查询报错信息里包含this is incompatible with sql_modeonly_full_group_by。通常是因为你把某个非聚合字段放进了SELECT但它不在GROUP BY里。我看到有些文章建议把sql_mode修改掉把ONLY_FULL_GROUP_BY去掉。我的建议是不要动配置。生产环境默认开启这个模式你改了本地配置等于在真实环境里用另一套规则写SQL迟早出事。正确做法是规范SQL写法SELECT里每个非聚合字段要么被聚合函数包裹要么出现在GROUP BY里。如果业务确实需要“每个分组里某列的具体值”那就用子查询或者窗口函数实现而不是绕开模式限制。5.2 字符集乱码三层要统一有一阵子我刷题时发现插入中文后查询结果全是问号一度怀疑是客户端问题。后来排查下来是建库时没指定字符集默认用了latin1。解决办法是在建库、建表时统一指定utf8mb4CREATE DATABASE study_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;还要确认客户端连接字符集。如果你使用命令行客户端可以执行SET NAMES utf8mb4;这三层分别是库表字符集、客户端连接字符集、终端显示字符集。任何一个不一致都可能出现乱码。这套100题里如果包含中文数据乱码问题会直接影响结果判断所以建库时统一字符集是很省心的一步。5.3 日期函数的边界值陷阱这套题里日期函数出现的频率比想象中高。我踩过的典型坑有两个第一个是DATE_FORMAT()返回的是字符串。比如DATE_FORMAT(create_time, %Y-%m-%d)返回结果看起来像日期但它其实是一串字符。如果你把这个结果直接和日期类型比较MySQL会做隐式转换在某些条件下结果不可预期。处理方式是能不用就不用或者用CAST()显式转换。第二个是DATEDIFF()的顺序问题。DATEDIFF(2024-01-03, 2024-01-01)结果是2是前面的日期减后面的日期。如果你写成DATEDIFF(2024-01-01, 2024-01-03)得到的就是负数。很多人在判断“距今超过N天”时把参数顺序写反导致数据异常。真正常用的写法是SELECT * FROM orders WHERE DATEDIFF(NOW(), create_time) 30;这句话的意思是创建时间距离现在已经超过30天。方向对了逻辑才成立。5.4 关联表数据爆炸JOIN后行数变多还有一种不报错但结果明显不对的情况LEFT JOIN之后结果行数比左表多。比如订单表一对一关联订单详情表按理说行数不变但如果订单详情表中一个订单对应多条记录左表订单就会重复出现。排查思路是先单独查两张表的行数再分组统计关联字段的重复次数最后把JOIN条件拆开看是否有遗漏的关联键。我在刷题时遇到一道“每个顾客最近一笔订单”的题目就是先用了LEFT JOIN结果因为订单表里一个顾客有多个订单查询结果带了重复行。后来换成窗口函数取ROW_NUMBER()干净利落地解决了问题。这里也再次印证碰到“取每个分组最新一条”的场景窗口函数是首选。6. 刷完100题之后下一步怎么走6.1 灌入真实量级的数据重新看一遍题目基础100题里的表通常很小几行几十行怎么写都快感受不到性能压力。我刷完后做的一件事是自己写了一个存储过程给订单表插入了50万行数据再回头跑之前那些JOIN和子查询的题目。你会发现有些解法在数据量小的时候没问题数据量一大就慢得离谱而用EXPLAIN看执行计划能看到走没走索引的差别。灌数据的方法很简单可以写个循环插入DELIMITER $$ CREATE PROCEDURE insert_test_data() BEGIN DECLARE i INT DEFAULT 1; WHILE i 500000 DO INSERT INTO orders(customer_id, amount, create_time) VALUES (MOD(i, 1000), RAND() * 1000, TIMESTAMP(2024-01-01) INTERVAL i SECOND); SET i i 1; END WHILE; END$$ DELIMITER ;注意一次插入50万行时尽量关闭自动提交用事务包裹不然会很慢。造完数据后针对之前做题时的SQL做EXPLAIN分析重点看type是否用到索引rows是否预估准确有没有出现Using filesort或者Using temporary。这两个标记是性能隐患的预警信号。6.2 从会写SQL到会分析慢SQL刷完题、有数据量基础后我建议把MySQL的慢查询日志打开。这是一条进阶路径也是从“会写”到“会调优”的必经之路。看一下慢SQL长什么样比如SELECT customer_id, COUNT(*) FROM orders WHERE DATE(create_time) 2024-01-01 GROUP BY customer_id;这条SQL的问题在于DATE(create_time)包裹了索引列导致索引无法使用。优化写法通常是把范围条件改写成WHERE create_time 2024-01-01 00:00:00 AND create_time 2024-01-02 00:00:00这其实不是100道题里的内容但它是刷题后顺手就能学的技能。因为你在基础题里已经熟悉了表结构和常用查询此时再来理解索引失效、覆盖索引、回表这些概念会比从零开始看容易很多。6.3 去真实业务里用脏数据磨炼最后说句实话100道题只是起点。真实的业务表里会有软删除标记、冗余字段、奇葩的历史数据、一张表存多种业务类型的坏设计。你可能会拿到一张看起来很像练习题里的表但实际写起来处处是坑。我的建议是刷完题之后尽快找一些真实场景来练手。比如自己写个小项目设计几张有关联的表用程序往里造数据然后模拟报表需求写查询。哪怕数据量不大也能帮你把练习题里的经验迁移到实际场景中。SQL能力的提升没有终点但这套100题是一个足够靠谱的起点。我个人刷完这套题后最大的感受是写SQL没有捷径但正确的训练方法能让你少走很多弯路。先手写、再执行、复盘错题、核对执行计划这套流程坚持下来你会发现那些曾经让你头疼的排序、分组、关联问题慢慢都会变成条件反射。如果你正打算系统练一遍SQL基础别贪多把这一百道题扎扎实实过两遍效果比泛泛刷几百道杂题好得多。
RELATED

相关推荐

LeetCode 1148 文章浏览 I:SQL条件过滤、去重与排序的经典实战

LeetCode 1148 文章浏览 I:SQL条件过滤、去重与排序的经典实战

这道题我有一个很深的印象——不是因为解法复杂,恰恰相反,它是不少人在LeetCode上接触的第一道数据库题:表结构简单、逻辑直白、最后只输出去重后的ID列表。“1148. 文章浏览 I”看起来简单到有点像是在送分,但它其实把SQL查询里最…

📅 2026/10/15 5:02:55
易语言乐玩插件多线程索引方案:告别串线崩溃,稳定并发找图

易语言乐玩插件多线程索引方案:告别串线崩溃,稳定并发找图

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/15 5:02:55
飞火动态壁纸从下载到配置:全程避坑实操指南

飞火动态壁纸从下载到配置:全程避坑实操指南

1. 从零开始:飞火动态壁纸到底能做什么说实话,我最早接触飞火动态壁纸的时候,心里是有疑问的——不就是个壁纸软件吗?能玩出什么花来?直到我真正装完、配好之后,才发现这事比我想象的要复杂,也远…

📅 2026/10/15 4:57:55
MORE NEWS

更多资讯

📰

PyTorch核心设计原理与工业级训练实践

1. 这不是“学个框架”那么简单:PyTorch到底在解决什么真实问题?很多人第一次听说PyTorch,是在某次技术分享会上听到“动态图好调试”“API设计更Pythonic”这类评价;也有人是从Kaggle竞赛排行榜上看到大量Top方案的代码仓库里&am…

📰

从零搭建大学生就业信息管理系统:需求、设计到实现

1. 这个系统解决什么问题:需求拆解与功能边界大学生就业信息管理系统我接触得比较多,每年都会看到不少计算机相关专业的同学拿它当毕设选题。第一反应往往是“这不就是一个信息管理的增删改查吗”,但真正动手做起来才会发现,角色权…

📰

TensorFlow全流程实战:从环境搭建到模型部署的完整链路

这不是一篇入门教程,也不是API文档搬运。从我第一次在项目里跑通TensorFlow,到现在能用它顺畅地完成从数据准备到模型部署的全流程,中间绕了很远的路,也踩了不少坑。这篇文章把你真正会用到的那些东西——环境、数据、模型、训练、…

📰

airllm:低显存机器跑超大语言模型的实践指南

实际测试完成的部署方案:如何在低内存机器上跑超大容量语言模型最近 AI 本地部署群里讨论最多的一个话题,不是新模型的评测,而是“我到底要多少显存才能跑得动这些模型”。动不动几十GB的权重,让很多人的消费级电脑直接劝退。如果…

📰

RAR归档文件解压全指南:从格式识别到批量处理与避坑

简介:GC-PowerStation 2019中文版是面向表面贴装工艺工程师的坐标导出与光绘文件处理工具,支持导入电子表格、文本等多种坐标文件格式,并完成多层光绘文件的预览、合并与校验,帮助电子制造从业者在生产前检查设计准确性&#xff0…

📰

易语言乐玩插件窗口句柄获取与后台绑定模式实战指南

1. 窗口句柄获取与后台绑定模式的核心逻辑拆解1.1 为什么窗口句柄是一切自动化操作的起点做桌面自动化或者辅助工具开发,绕不开的第一个坎就是拿到目标窗口的句柄。你可以把窗口句柄理解成操作系统给每个窗口发的一张身份证号,它是一个长整型数值&#x…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬