SQL练习题刷题指南:从单表查询到窗口函数的避坑与进阶

发布时间:2026/10/13 9:00:59

SQL练习题刷题指南:从单表查询到窗口函数的避坑与进阶 简介这是一份SQL语句练习题及答案文档适合正在学习关系型数据库、希望系统强化SQL能力的学生与开发者。题目以School数据库中的Student、Course、SC三张表为背景从建表、插入、删除、更新入手逐步覆盖单表查询、分组统计、多表连接、嵌套查询与相关子查询等经典考点难度由浅入深并配有参考答案方便对照核验、查漏补缺。资源包内共1个doc文件仅43KB容量小、打开即用适合放入手机或电脑反复翻阅。该资源已有520人学习浏览虽然文档体量轻巧但胜在专题集中、覆盖完整可作为SQL入门练习和考前复习的实用配套资料。1. sql语句练习题及答案.doc为什么刷题比背语法更快建立SQL直觉很多开发者在面试前会翻出这份经典的《sql语句练习题及答案.doc》却大多只是从头到尾看一遍答案然后进考场照样写不出 JOIN。这个标题背后其实是一套“题目 参考答案”的配套训练包它要解决的痛点很具体SQL 语法看着都会一动手就卡壳。这份文档的价值不在于题目本身而在于它把知识点拆成了可反复练习的最小单元让你在笔试和实际开发前把 SELECT、聚合、连接、子查询这些高频操作变成肌肉记忆。适合三类人准备数据库笔试的应届生、写业务代码但 SQL 靠百度的后端开发以及需要日常取数的测试和运维。2. 拆开一份SQL习题集单表查询、聚合分组、多表连接、子查询与窗口函数拿到一份 SQL 练习题集先别急着从头做。常见的习题集看起来题目很多但围绕的核心知识点基本固定条件过滤、聚合分组、多表连接、子查询、窗口函数。这五个点之所以被反复考是因为它们对应日常取数的绝大多数场景——查明细、做统计、关联多表、处理排名和环比。下面用一套统一的数据表把每类题型过一遍你只需要在本地建好这两张表就能跟着题目走。先用下面的建表语句搭好练习环境。这里刻意不指定数据库引擎因为在 mysql 和 sql server 下这套标准 SQL 都能跑个别函数差异会在后面章节单独说明。-- 员工表 CREATE TABLE emp ( id INT PRIMARY KEY, name VARCHAR(50), dept_id INT, salary DECIMAL(10, 2), hiredate DATE ); -- 部门表 CREATE TABLE dept ( dept_id INT PRIMARY KEY, dept_name VARCHAR(50) ); -- 插入样例数据第 7 条故意不给部门用于演示连接 INSERT INTO emp VALUES (1, 张伟, 1, 12000, 2021-03-01), (2, 李娜, 1, 15000, 2020-07-15), (3, 王强, 2, 9000, 2022-01-10), (4, 赵敏, 2, 11000, 2021-11-20), (5, 孙磊, 3, 7000, 2023-05-06), (6, 周芳, 2, 9000, 2020-12-01), (7, 吴峰, NULL, 8000, 2023-08-01); INSERT INTO dept VALUES (1, 研发部), (2, 市场部), (3, 人事部);建表后建议先用 SELECT * 确认数据能正常读出来再开始做题。这套数据量虽小但足够覆盖五类题型中绝大多数边界情况尤其是那条 dept_id 为 NULL 的员工数据后面会反复用到。2.1 单表查询与条件过滤WHERE、LIKE、IN与NULL的判断第一类题型最简单但也最容易在细节上丢分条件过滤。这道题想考的是模糊匹配和空值判断。题目查询市场部中工资大于 9000 且姓名以“赵”开头的员工。SELECT id, name, salary FROM emp WHERE dept_id 2 AND salary 9000 AND name LIKE 赵%;这里的关键点在于 LIKE 的写法’赵%’ 匹配以“赵”开头的任意字符串% 代表任意长度的字符而 _ 只代表一个字符。很多人会把“赵%”写成“%赵%”导致查出所有姓名里带“赵”的人结果范围被放大。另一个容易忽略的是 NULL 判断如果题目要求“查出没有部门的员工”那条件必须是 dept_id IS NULL而不能写成 dept_id NULL。在 SQL 里NULL 不等于任何值也不等于它自己这个边界几乎每份习题集都会用来做陷阱。2.2 聚合与分组COUNT、GROUP BY、HAVING的顺序陷阱第二类题型是聚合统计考点集中在 GROUP BY 与 HAVING 的配合。题目统计每个部门的平均工资且只保留平均工资大于 9000 的部门。SELECT dept_id, AVG(salary) AS avg_salary FROM emp WHERE dept_id IS NOT NULL GROUP BY dept_id HAVING AVG(salary) 9000;先解释执行顺序SQL 先执行 FROM 和 WHERE 过滤掉 NULL 部门然后 GROUP BY 按部门分组再计算每组 AVG(salary)最后 HAVING 把平均工资小于等于 9000 的组删掉。这里最容易翻车的是把过滤条件写在 HAVING 里比如“只统计工资大于 8000 的员工”这个条件应该放 WHERE而不是 HAVING。两者的区别在于WHERE 在分组前过滤行HAVING 在分组后过滤组。当你发现统计结果和预期差很多时优先检查条件是不是放错了位置。另外注意 SELECT 里出现的非聚合列必须出现在 GROUP BY 中否则 MySQL 5.7 之后的版本会直接报错这也是 sql 语句去重之外的另一个高频报错点。2.3 多表连接INNER JOIN与LEFT JOIN的实战选择多表连接是笔试区分度的核心。题目查出所有员工及其部门名称包括没有部门的员工。SELECT e.id, e.name, e.salary, d.dept_name FROM emp e LEFT JOIN dept d ON e.dept_id d.dept_id;这里选 LEFT JOIN 是为了保留 emp 表中未匹配上的行也就是员工“吴峰”的记录他的 dept_name 会是 NULL。如果把 LEFT JOIN 换成 INNER JOIN这条数据会被直接丢弃结果少一行。我在实际开发中总结的经验是只要听到“所有员工都查出来”“包括没有部门的”第一反应就该用 LEFT JOIN并根据业务决定主表位置。连接条件也要看清是 ON e.dept_id d.dept_id而不是在 WHERE 里写等值条件——虽然结果一样但语义不清晰且 LEFT JOIN 时把连接条件放 WHERE 会让左连接退化成内连接这是个非常隐蔽的坑。2.4 子查询与EXISTS什么时候用EXISTS而不是IN第四类题型是子查询考点在 IN 与 EXISTS 的选择。题目查询工资高于研发部平均工资的员工名单。SELECT id, name, salary FROM emp WHERE salary ( SELECT AVG(salary) FROM emp WHERE dept_id 1 );标量子查询返回单行单列这种写法最直观但需要你理解子查询的执行顺序先查部门 1 的平均工资再把这个结果作为外层 WHERE 的过滤条件。另一类高频题是“查出哪些部门下面没有员工”这种适合用 NOT EXISTSSELECT dept_id, dept_name FROM dept d WHERE NOT EXISTS ( SELECT 1 FROM emp e WHERE e.dept_id d.dept_id );NOT EXISTS 是关联子查询它逐行拿 dept 表的 dept_id 去 emp 表里找匹配找到就跳过。很多人习惯用 NOT IN但一旦 emp.dept_id 里存在 NULLNOT IN 会返回空结果因为 NULL 导致整个判断变成不确定。所以遇到“存在性判断”我一般优先写 EXISTS少一个坑。这个知识点在很多 SQL 面试题里都是送命题。2.5 窗口函数ROW_NUMBER、RANK、DENSE_RANK的高频考法窗口函数是近几年面试题里的新宠。题目按工资从高到低给员工排名要求工资相同的人名次连续。SELECT id, name, salary, RANK() OVER (ORDER BY salary DESC) AS rk, DENSE_RANK() OVER (ORDER BY salary DESC) AS drk, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn FROM emp;结果里 9000 元的王强和周芳会分别得到RANK 是 3、3下一名跳成 5DENSE_RANK 是 3、3下一名是 4ROW_NUMBER 是 3、4不关心并列。面试官问“取每个部门工资最高的员工”标准答案就是用 ROW_NUMBER() 配合 PARTITION BY dept_id再在外面包一层查询筛选 rn 1。窗口函数掌握的关键就三个词PARTITION BY 分组、ORDER BY 排序、以及选对排名函数。很多人背了语法却选错函数就是没搞懂这三个函数对并列值的处理差异。3. 把练习题变成肌肉记忆先做后看答案、一题多写、换引擎验证题目看懂了离真正会用还差一步。同一道练习题有人做一遍就忘有人做一遍能顶十遍差别就在刷题方法。这一章不讲新语法只讲怎么把手里的习题集物尽其用。3.1 先做后看答案把答案当裁判而不是教材我看到太多人打开习题集先看答案再看题看完觉得自己“懂了”关掉文档写不出来。正确做法是拿一张纸盖住答案列先自己写。写不出来可以翻书、查函数定义但不要偷看答案。哪怕只写出一个半成品也比直接看答案强——因为半成品暴露了你卡在哪一步是 JOIN 方向反了还是忘了 GROUP BY。写完再对答案重点看三处你的结果和标准结果是否一致你的写法和答案的写法哪个更简洁答案里有没有你没想到的函数。这一步是把“看懂了”变成“会写了”的分水岭。3.2 一题多写用JOIN改写子查询、用窗口函数改写GROUP BY一道题只写一种解法你的能力边界就停在那个写法上。我自己的习惯是每道题至少用两种方式实现同一结果。比如“查出每个部门工资最高的员工”可以用子查询加 IN也可以用窗口函数加 ROW_NUMBER两种写法都能跑出正确结果但执行效率差别很大。再比如练习去重分组时既可以用 GROUP BY 加 MAX也可以用 ROW_NUMBER 加 PARTITION BY。多写一遍的最大价值不是炫技而是让你在真实业务里遇到同类型需求时脑子里能同时冒出两条路一条跑不通就换另一条。3.3 换引擎验证在mysql和sql server下跑同一道题习题集的答案通常基于标准 SQL 书写但实际工作环境往往是 mysql 或 sql server。我有一个建议把自己写的 SQL 拿到两个引擎里各跑一遍你会有意外收获。比如分页场景mysql 用 LIMIT 10 OFFSET 5sql server 用 OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY字符串拼接mysql 用 CONCATsql server 用加号。平时练习时可以用 navicat 连接本地 mysql 执行脚本也可以打开 sql server management studio 直接跑练习题的建表语句。同一套数据在两个引擎里跑出的结果一致但写法和报错信息完全不同。这种差异早踩早安心总比上了生产环境被语法报错打个措手不及要好。提示建表语句里如果用了 AUTO_INCREMENTsql server 里要改成 IDENTITY(1,1)这是换引擎后最常遇到的第一个报错。4. 刷题踩坑记录NULL、去重、HAVING边界与排名函数的五个坑刷题最气人的不是题不会做而是答案看着没问题结果就是和参考答案对不上。下面五个坑是我在带新人时几乎每期都要讲一遍的每一条都有真实翻车案例。4.1 COUNT(*)与COUNT(字段)结果对不上NULL在捣乱现象统计员工数量时SELECT COUNT(*) 返回 7SELECT COUNT(dept_id) 返回 6两份结果不一致以为是数据出错了。原因COUNT() 统计的是行数不管字段是否为 NULL而 COUNT(dept_id) 只统计 dept_id 非空的行数。样例数据里“吴峰”的 dept_id 是 NULL被 COUNT(字段) 自动跳过了。这在做报表统计时非常常见比如统计订单量用 COUNT()统计有退款记录的订单数用 COUNT(refund_time)两者差出来的就是待处理退款。解决先想清楚题目要的是行数还是非空值数量再决定用哪种写法。如果只是想统计分组内有多少条记录一律用 COUNT(*)不要把字段名写进去。4.2 不去重导致结果对不上答案重复行是最大翻车点现象查询所有员工的工资等级结果比参考答案多出一行。原因练习表里王强和周芳的工资都是 9000如果题目问“列出所有工资值”直接 SELECT salary 会返回两条 9000而参考答案用的是 SELECT DISTINCT salary。很多 SQL 语句去重场景下不加 DISTINCT 不报错但结果就是错的。解决每道题写完先扫一眼如果题目里出现“不同”“去重”“有哪些”这类字眼第一反应是加 DISTINCT或者在 GROUP BY 里把这些列带上。这里强调一点DISTINCT 是作用于整行的SELECT DISTINCT a, b 是对 a 和 b 的组合去重不是只对 a 去重。4.3 HAVING和WHERE写反分组前过滤与分组后过滤的边界现象统计平均工资大于 9000 的部门结果少了市场部因为市场部被一个低工资员工拉低了平均值。新人把“工资大于 8000 才参与统计”这个条件写进了 HAVING导致过滤时机不对。原因WHERE 在分组前执行删除的是原始行HAVING 在分组后执行删除的是整个分组。如果把“只统计工资大于 8000 的员工”写成 HAVING salary 8000会因为 salary 不是聚合列而报错或者被当成对聚合结果的错误判断。解决判断条件里如果涉及单行字段值如 salary、hiredate就放进 WHERE如果涉及聚合值如 AVG(salary)、COUNT(id)就必须用 HAVING。这个边界理不清后续遇到慢 SQL 优化时也会无从下手因为过滤阶段不同直接决定扫描行数。4.4 RANK跳号不是答案错三种排名函数的排序边界现象用 RANK() 做工资排名结果 9000 元的两个人并列第 3下一个直接变成第 5。有人以为这是函数没用对反复检查语句。原因RANK() 的设计就是“并列后跳号”这是标准行为不是 bug。DENSE_RANK() 不跳号ROW_NUMBER() 不给并列名次。三种函数对应不同的业务场景比赛排名用 RANK榜单展示用 DENSE_RANK取前 N 条唯一记录用 ROW_NUMBER。解决选函数前先问一句工资相同的人领导希望看到“并列第 3、下一名第 5”还是“并列第 3、下一名第 4”想清楚再写。这个问题在面试里只要答出“RANK 会跳号、DENSE_RANK 不跳”基本就能过。4.5 LIMIT和TOP混着背跨数据库改错语法现象在 mysql 里写好的 SELECT TOP 5 name FROM emp直接拿到 sql server 里跑报语法错误反过来把 sql server 的写法拿到 mysql 里也报错。原因两个引擎的分页语法完全不同。mysql 用 LIMIT 关键字sql server 2012 之后用 OFFSET...FETCH老版本还要用 TOP 加子查询绕。习题集一般用标准 SQL 写但不会告诉你哪种写法在哪个引擎下能跑。这个坑在换引擎验证那一步暴露得最明显。解决练习时就给自己定个规矩同一道题在 mysql 和 sql server 各写一遍。mysql 的分页可以直接在查询末尾加 LIMIT 5 OFFSET 0sql server 里要写成 OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY。多写一次比临到生产环境再去翻文档强得多。5. 从练习题到面试把答案讲出口的进阶技巧练习题刷对了下一步是把它转化成面试里能讲清楚的能力。很多人笔试能写对一到口试环节就卡住比如面试官问“你这个查询是怎么执行的”答不上来。这一章分享两个我自己常用的进阶技巧。5.1 对着答案默写执行顺序直到脱稿每做完一道题不要急着做下一道先对着自己写的 SQL 说一遍执行顺序先 FROM 找表再 WHERE 过滤行接着 GROUP BY 分组HAVING 过滤组然后 SELECT 算列最后 ORDER BY 排序。能顺畅说出来的说明你真正理解了这条语句。说不出来的回去翻章节 2.2 的执行顺序说明把它背到脱口而出。这个习惯帮我应付过好几次面试面试官问“这个查询为什么先 WHERE 后 HAVING”我能直接讲出过滤时机不同导致结果差异。笔试是闭卷口试是开卷但开卷题往往比闭卷题更考验基本功。5.2 把简单题改造成慢SQL场景用执行计划验证进阶的做法是把练习题里的 SQL 改造成实际业务里会遇到的慢 SQL 场景。比如章节 2.1 里的“查工资大于 9000 的员工”你可以想象成一张百万行的订单表给 salary 字段建索引和不建索引执行计划差别巨大。在 mysql 里用 EXPLAIN SELECT ... 看 type 字段是 ALL 还是 ref在 sql server 里用“显示估计的执行计划”看有没有走索引查找。这个技巧能帮你把练习题的价值延伸到慢 SQL 优化领域——面试官问“你平时怎么定位慢查询”你直接说“先在练习题环境里用 EXPLAIN 验证索引是否生效”比背概念真实得多。最后说一个我自己的教训早年刷这份习题集只追求“答案对”没追求“讲得清”结果面试时被问到一条子查询的执行顺序当场语塞。从那以后我养成了一个习惯——凡是写过的 SQL都要能用自己的话把执行过程完整讲出来。这个习惯如今也在帮我写复杂报表时少走弯路。希望这份练习题的刷法能帮到你把 SQL 从“看会的”变成“写对的、讲得清的”。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/12 6:45:08

SpringBoot高校党建系统实战:状态机、权限控制与Docker部署

这项目我前后做了将近两个月,真正交付那天,反而没有太多兴奋感,就是觉得这类系统做完,人对“业务流程”这四个字的理解会完全不一样。高校大学生党建系统,听起来是一个行政味很重的项目,但它本质上是一套非…

2026/10/13 8:58:29

AI芯片软硬件协同设计:从算子特征到硬件架构的映射与优化

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

2026/10/13 9:00:17

圆弧趋近直线时的圆心与半径极限分析

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

2026/10/13 9:00:17

ComfyUI本地部署全指南:从硬件要求到实战优化

说实话,ComfyUI是我用过所有AI绘图工具里“入门门槛最低、天花板最高”的一个。低是因为装好之后跑第一张图的流程跟开游戏差不多,双击启动,拖个工作流,点运行,图就出来;高是因为想复现网上那些复杂到能自动…

2026/10/13 9:00:17

多Agent自动化模板

# 基于 PostgreSQL xxxxxxx 的 xxxx 标量混合搜索索引:多 Agent 协同示例## 一、目标形式化与验收标准### 1.1 总目标设计并实现一个xxxxxxxxxxxxxxxx。### 1.2 成功标准(可验证)| 编号 | 验收项 | 验证方式 | |------|--------|----------|…

2026/10/13 9:00:17

水杉2.4.8低模建模实战:安装激活、操作技巧与Blender联动

简介:Metasequoia 2.4.8繁体版是一款专为繁体中文用户打造的三维建模与动画制作工具,由日本公司开发,昵称“水杉”,其完全汉化的界面免去了语言障碍,适合从初学者到专业美术师等不同层级的创作者使用。压缩包共含152个…

2026/10/13 8:55:17

工业影像制作:技术翻译与视觉表达的艺术

1. 工业影像领域的专业深耕者在制造业转型升级的大背景下,工业影像作为企业品牌传播和技术展示的重要载体,其专业价值日益凸显。中之网科技作为这个细分领域的深耕者,20年来始终专注于工业制造类企业宣传片的拍摄制作,形成了独特的…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑