Interview AiBoxInterview AiBox 实时 AI 助手,让你自信应答每一场面试
SQL面试完全指南:30道高频题+标准答案解析
30道高频SQL面试题,覆盖基础查询、JOIN、聚合函数、窗口函数;每题含标准答案、解析和面试官视角,帮你把SQL从会写变成会讲。
- sellSql
- sellDatabase
- sellInterview Questions
SQL面试完全指南:30道高频题+标准答案解析
Stack Overflow 2024年开发者调查显示,SQL连续多年稳居最常用编程语言前三,超过50%的专业开发者在工作中使用SQL。无论你申请数据分析师、后端工程师还是数据工程师岗位,SQL都是绕不开的技能。
但很多人刷了上百道LeetCode SQL题,面试时还是卡壳。为什么?因为面试官考察的不只是你会不会写,而是你怎么思考、如何优化、能否应对真实业务场景。
这篇文章整理了30道高频SQL面试题,按难度和知识点分类,每道题都附带标准答案、解析和面试官视角。看完这篇,你就知道SQL面试到底在考什么。
一、基础查询(10题)
查询所有列和指定列
题目:有一个employees表,包含id, name, department, salary, hire_date字段。请写出查询所有员工信息的SQL,以及只查询姓名和部门的SQL。
答案:
-- 查询所有列
SELECT * FROM employees;
-- 查询指定列
SELECT name, department FROM employees;解析:
SELECT *会返回所有列,生产环境慎用(性能问题)- 明确列出需要的列是更好的实践
面试官视角:这道题看起来简单,但我会追问"为什么不用SELECT *",考察你是否了解生产环境的最佳实践。
WHERE条件筛选
题目:查询薪资大于50000的员工姓名和薪资。
答案:
SELECT name, salary
FROM employees
WHERE salary > 50000;解析:
WHERE子句用于过滤行- 支持的比较运算符:
=, >, <, >=, <=, <>, !=
多条件筛选(AND/OR)
题目:查询IT部门且薪资大于60000的员工,或者任何部门薪资大于100000的员工。
答案:
SELECT *
FROM employees
WHERE (department = 'IT' AND salary > 60000)
OR salary > 100000;解析:
- 使用括号明确优先级
AND优先级高于OR,不写括号可能得到错误结果
面试官视角:我会故意不写括号,看候选人能否发现逻辑错误。
IN和BETWEEN
题目:查询部门为IT、HR或Finance的员工,以及入职日期在2020-01-01到2023-12-31之间的员工。
答案:
SELECT *
FROM employees
WHERE department IN ('IT', 'HR', 'Finance')
AND hire_date BETWEEN '2020-01-01' AND '2023-12-31';解析:
IN可以替代多个OR,更简洁BETWEEN是闭区间,包含两端值
LIKE模糊匹配
题目:查询姓名以"J"开头的员工。
答案:
SELECT *
FROM employees
WHERE name LIKE 'J%';解析:
%匹配任意多个字符_匹配单个字符LIKE 'J%n'匹配以J开头、以n结尾的姓名
NULL值处理
题目:查询没有分配部门的员工(department字段为NULL)。
答案:
SELECT *
FROM employees
WHERE department IS NULL;解析:
NULL不能用= NULL或<> NULL判断- 必须用
IS NULL或IS NOT NULL - 任何与NULL的比较都返回NULL(不是TRUE也不是FALSE)
面试官视角:这是高频错误点,很多候选人会写成= NULL,我会追问"为什么这样写不对"。
ORDER BY排序
题目:查询所有员工,按薪资降序排列,薪资相同的按姓名升序排列。
答案:
SELECT *
FROM employees
ORDER BY salary DESC, name ASC;解析:
DESC降序,ASC升序(默认)- 可以按多个字段排序,优先级从左到右
LIMIT限制结果
题目:查询薪资最高的3名员工。
答案:
SELECT *
FROM employees
ORDER BY salary DESC
LIMIT 3;解析:
- MySQL/PostgreSQL用
LIMIT - SQL Server用
TOP 3 - Oracle用
FETCH FIRST 3 ROWS ONLY
DISTINCT去重
题目:查询公司有哪些部门(不重复)。
答案:
SELECT DISTINCT department
FROM employees;解析:
DISTINCT作用于整行,不是单个列SELECT DISTINCT department, salary会按两列组合去重
别名(AS)
题目:查询员工姓名和年薪(薪资×12),列名显示为"员工姓名"和"年薪"。
答案:
SELECT name AS 员工姓名,
salary * 12 AS 年薪
FROM employees;解析:
AS可以省略- 别名可以用中文,但建议用英文
- 别名可以在
ORDER BY中使用
二、JOIN连接查询(8题)
INNER JOIN内连接
题目:有employees和departments两张表,查询每个员工的姓名及其部门名称。
答案:
SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;解析:
INNER JOIN只返回两表都有匹配的行- 表别名让SQL更简洁
- 连接条件用
ON指定
LEFT JOIN左连接
题目:查询所有员工的姓名和部门名称,包括没有分配部门的员工。
答案:
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;解析:
LEFT JOIN返回左表所有行,右表没有匹配则为NULL- 这是实际业务中最常用的JOIN类型
面试官视角:我会问"INNER JOIN和LEFT JOIN的区别",以及"什么场景用LEFT JOIN"。
RIGHT JOIN右连接
题目:查询所有部门及其员工,包括没有员工的部门。
答案:
SELECT d.department_name, e.name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.id;解析:
RIGHT JOIN与LEFT JOIN对称- 实际中很少用,可以改写成
LEFT JOIN(交换表顺序)
FULL OUTER JOIN全连接
题目:查询所有员工和所有部门,无论是否匹配。
答案:
-- PostgreSQL/SQL Server
SELECT e.name, d.department_name
FROM employees e
FULL OUTER JOIN departments d ON e.department_id = d.id;
-- MySQL不支持FULL JOIN,用UNION替代
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id
UNION
SELECT e.name, d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.id;解析:
FULL OUTER JOIN返回两表所有行- MySQL不支持,需要用
UNION模拟
自连接
题目:employees表有id, name, manager_id字段,查询每个员工及其直接上级的姓名。
答案:
SELECT e.name AS 员工姓名,
m.name AS 上级姓名
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;解析:
- 自连接是同一张表与自己连接
- 通过别名区分两个"副本"
- 常用于层级关系查询
多表连接
题目:有employees, departments, projects三张表,查询员工姓名、部门名称和参与的项目名称。
答案:
SELECT e.name, d.department_name, p.project_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id
LEFT JOIN employee_projects ep ON e.id = ep.employee_id
LEFT JOIN projects p ON ep.project_id = p.id;解析:
- 可以连续JOIN多张表
- 注意连接顺序和条件
- 多对多关系需要中间表
CROSS JOIN交叉连接
题目:生成所有员工和所有部门的组合(笛卡尔积)。
答案:
SELECT e.name, d.department_name
FROM employees e
CROSS JOIN departments d;解析:
CROSS JOIN返回两表的笛卡尔积- 结果行数 = 表A行数 × 表B行数
- 实际业务中很少用,通常是无意的错误
JOIN性能优化
题目:为什么JOIN查询很慢?如何优化?
答案:
-- 确保连接字段有索引
CREATE INDEX idx_emp_dept ON employees(department_id);
CREATE INDEX idx_dept_id ON departments(id);
-- 只查询需要的列
SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
WHERE e.salary > 50000;解析:
- 连接字段建立索引
- 小表驱动大表
- 避免
SELECT * - 先过滤再连接
面试官视角:这道题考察实战经验,我会追问"如何分析慢查询"。
三、聚合函数与分组(7题)
基本聚合函数
题目:查询员工总数、平均薪资、最高薪资、最低薪资、薪资总和。
答案:
SELECT COUNT(*) AS 员工总数,
AVG(salary) AS 平均薪资,
MAX(salary) AS 最高薪资,
MIN(salary) AS 最低薪资,
SUM(salary) AS 薪资总和
FROM employees;解析:
COUNT(*)统计行数COUNT(column)统计非NULL值数量AVG自动忽略NULL值
GROUP BY分组
题目:查询每个部门的员工数量和平均薪资。
答案:
SELECT department,
COUNT(*) AS 员工数量,
AVG(salary) AS 平均薪资
FROM employees
GROUP BY department;解析:
GROUP BY按指定列分组- SELECT中的非聚合列必须出现在GROUP BY中
- 分组后每组返回一行
HAVING过滤分组
题目:查询员工数量超过5人的部门。
答案:
SELECT department, COUNT(*) AS 员工数量
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;解析:
WHERE过滤行,HAVING过滤分组WHERE在分组前,HAVING在分组后HAVING可以使用聚合函数
面试官视角:我会问"WHERE和HAVING的区别",这是经典面试题。
GROUP BY多列
题目:查询每个部门每个职级的员工数量。
答案:
SELECT department, level, COUNT(*) AS 员工数量
FROM employees
GROUP BY department, level;解析:
- 可以按多列分组
- 分组粒度更细
GROUP BY与ROLLUP
题目:查询每个部门的薪资总和,以及所有部门的总薪资。
答案:
SELECT department, SUM(salary) AS 薪资总和
FROM employees
GROUP BY department WITH ROLLUP;解析:
WITH ROLLUP生成小计和总计行- 总计行的department为NULL
- MySQL/SQL Server支持,PostgreSQL用
GROUPING SETS
聚合函数与NULL
题目:employees表的bonus列有NULL值,计算平均奖金时如何处理?
答案:
-- 方法1:AVG自动忽略NULL
SELECT AVG(bonus) FROM employees;
-- 方法2:将NULL视为0
SELECT AVG(COALESCE(bonus, 0)) FROM employees;
-- 方法3:只计算有奖金的员工
SELECT AVG(bonus) FROM employees WHERE bonus IS NOT NULL;解析:
COALESCE(value, default)返回第一个非NULL值- 业务场景决定如何处理NULL
DISTINCT与聚合函数
题目:统计有多少个不同的部门。
答案:
SELECT COUNT(DISTINCT department) AS 部门数量
FROM employees;解析:
COUNT(DISTINCT column)统计不重复值的数量- 可以与其他聚合函数组合:
SUM(DISTINCT salary)
四、窗口函数(5题)
ROW_NUMBER排名
题目:为每个部门的员工按薪资排名,薪资相同的按姓名排序。
答案:
SELECT name, department, salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC, name
) AS 排名
FROM employees;解析:
ROW_NUMBER()生成连续序号,不会重复PARTITION BY分组,类似GROUP BY但不合并行ORDER BY组内排序
RANK和DENSE_RANK
题目:查询员工薪资排名,考虑并列情况。
答案:
SELECT name, salary,
RANK() OVER (ORDER BY salary DESC) AS rank排名,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank排名
FROM employees;解析:
RANK():并列时跳过后续名次(1,2,2,4)DENSE_RANK():并列时不跳过(1,2,2,3)ROW_NUMBER():不处理并列(1,2,3,4)
面试官视角:这是高频考点,我会问三种排名函数的区别。
LAG和LEAD
题目:查询每个员工与其前一名员工的薪资差。
答案:
SELECT name, salary,
LAG(salary) OVER (ORDER BY salary DESC) AS 前一名薪资,
salary - LAG(salary) OVER (ORDER BY salary DESC) AS 薪资差
FROM employees;解析:
LAG(column, offset, default)获取前N行的值LEAD(column, offset, default)获取后N行的值- 常用于计算环比、同比
SUM窗口函数
题目:计算累计薪资(按薪资降序)。
答案:
SELECT name, salary,
SUM(salary) OVER (
ORDER BY salary DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS 累计薪资
FROM employees;解析:
- 聚合函数可以用作窗口函数
ROWS BETWEEN ... AND ...定义窗口范围UNBOUNDED PRECEDING表示第一行
NTILE分组
题目:将员工按薪资分为4个等级(前25%、25%-50%、50%-75%、后25%)。
答案:
SELECT name, salary,
NTILE(4) OVER (ORDER BY salary DESC) AS 薪资等级
FROM employees;解析:
NTILE(n)将数据分为n组- 每组行数尽量相等
- 常用于分位数分析
五、面试官想看到什么
刷题只是第一步,面试官真正考察的是:
思维过程
面试官不会只看你写出正确答案,更看重你如何思考:
- 先理解需求:复述题目,确认边界条件
- 分析数据:问清楚表结构、数据量、NULL值处理
- 写出方案:先写基本版本,再优化
- 解释思路:说明为什么这样写
示例对话:
面试官:查询每个部门薪资最高的员工。
候选人:我需要确认一下,一个部门可能有多个员工薪资相同且最高吗?如果是,要返回所有最高薪的员工,还是只返回一个?
这种提问展示了你的业务思维和严谨性。
优化意识
写出能跑的SQL不难,难的是写出高效的SQL。面试官会考察:
索引意识:
-- 差:全表扫描
SELECT * FROM employees WHERE YEAR(hire_date) = 2023;
-- 好:利用索引
SELECT * FROM employees
WHERE hire_date >= '2023-01-01' AND hire_date < '2024-01-01';查询优化:
-- 差:子查询效率低
SELECT * FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = 'Beijing');
-- 好:JOIN效率高
SELECT e.*
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
WHERE d.location = 'Beijing';避免全表扫描:
- 只查询需要的列
- WHERE条件使用索引列
- 避免在索引列上使用函数
实战经验
面试官会通过追问考察你是否真正用过SQL:
- "遇到过最复杂的SQL查询是什么?"
- "如何优化一个执行了10秒的查询?"
- "如何处理大数据量的导出?"
- "MySQL和PostgreSQL的窗口函数有什么区别?"
准备一些真实案例,比背答案更有说服力。
边界情况处理
优秀的候选人会主动考虑边界情况:
- NULL值如何处理?
- 数据重复怎么办?
- 结果集为空会怎样?
- 大数据量会不会OOM?
-- 考虑NULL值
SELECT COALESCE(department, '未分配') AS 部门
FROM employees;
-- 考虑除零错误
SELECT department,
SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END) * 1.0 /
NULLIF(COUNT(*), 0) AS 男性比例
FROM employees
GROUP BY department;代码可读性
生产环境的SQL需要团队协作,可读性很重要:
-- 差:一行写完,难以理解
SELECT e.name,d.department_name,COUNT(*) FROM employees e JOIN departments d ON e.department_id=d.id JOIN employee_projects ep ON e.id=ep.employee_id GROUP BY e.name,d.department_name HAVING COUNT(*)>2;
-- 好:格式清晰,易于维护
SELECT
e.name AS 员工姓名,
d.department_name AS 部门名称,
COUNT(*) AS 项目数量
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
INNER JOIN employee_projects ep ON e.id = ep.employee_id
GROUP BY e.name, d.department_name
HAVING COUNT(*) > 2;六、常见问题FAQ
Q1: SQL面试一般考什么难度?
A: 取决于岗位:
- 数据分析师:基础查询、JOIN、聚合函数为主,偶尔考窗口函数
- 后端工程师:JOIN、索引优化、慢查询分析
- 数据工程师:窗口函数、复杂查询、性能优化、大数据处理
建议按岗位准备,不要盲目刷难题。
Q2: LeetCode SQL题要刷多少道?
A: 质量比数量重要。建议:
- Easy 50道:熟练基础语法
- Medium 30道:掌握JOIN、窗口函数
- Hard 10道:挑战复杂场景
重点不是刷多少,而是每道题都理解透彻,能举一三。
Q3: 不同数据库的SQL语法差异大吗?
A: 核心语法(SELECT, WHERE, JOIN, GROUP BY)基本一致,差异主要在:
| 功能 | MySQL | PostgreSQL | SQL Server | Oracle |
|---|---|---|---|---|
| 字符串连接 | CONCAT() | || | + | || |
| 限制行数 | LIMIT | LIMIT | TOP | FETCH FIRST |
| 布尔类型 | 无 | 有 | 无 | 无 |
| 窗口函数 | 8.0+支持 | 完整支持 | 完整支持 | 完整支持 |
| FULL JOIN | 不支持 | 支持 | 支持 | 支持 |
面试时可以问清楚用哪个数据库,针对性回答。
Q4: 如何快速提升SQL能力?
A: 三步走:
- 系统学习语法:看官方文档或教程,建立完整知识体系
- 动手实践:在真实数据集上练习(Kaggle、政府公开数据)
- 分析慢查询:用EXPLAIN分析执行计划,理解索引原理
推荐资源:
- SQLZoo:交互式练习
- Mode Analytics SQL Tutorial:实战导向
- 《SQL必知必会》:入门经典
Q5: 面试时手写SQL紧张怎么办?
A: 几个技巧:
- 先写伪代码:用中文描述逻辑,再翻译成SQL
- 分步写:先写主查询,再加JOIN、WHERE、GROUP BY
- 写完检查:语法、逻辑、边界情况
- 不会就说不会:诚实比瞎编好,可以说"这个语法我不太熟,但我知道思路是..."
Q6: SQL面试会考数据库设计吗?
A: 会,尤其是后端和数据岗位。常见问题:
- 设计一个电商订单系统的表结构
- 如何处理多对多关系?
- 什么时候用外键?什么时候不用?
- 如何设计索引?
建议学习基本的数据库设计原则:范式、反范式、索引设计。
Q7: 窗口函数这么重要,为什么很多人不会?
A: 两个原因:
- 历史原因:MySQL 8.0才支持窗口函数,很多教程和面试题还停留在旧版本
- 学习路径:很多人只学到GROUP BY就停了,窗口函数是进阶内容
但现在窗口函数是数据分析的必备技能,必须掌握。
Q8: 如何准备SQL现场编程(Live Coding)?
A:
- 提前熟悉环境:问清楚用什么工具(SQL Fiddle、本地数据库等)
- 边写边说:解释你的思路,展示思考过程
- 测试用例:写完后自己构造测试数据验证
- 时间管理:不要在一个问题上卡太久,可以先写简单版本再优化
七、如何用Interview AiBox准备SQL面试
刷题只是第一步,真正的挑战是:
- 如何系统学习:而不是零散地刷题
- 如何模拟面试:而不是只看不练
- 如何查漏补缺:而不是重复练习已掌握的知识
Interview AiBox 提供完整的SQL面试准备方案:
智能题库
- 500+ SQL面试题,按难度和知识点分类
- 每道题附带标准答案、解析、面试官视角
- 支持MySQL、PostgreSQL、SQL Server等多种数据库
AI模拟面试
- 真实面试场景模拟,AI扮演面试官
- 根据你的回答追问,考察思维深度
- 实时反馈,指出改进点
个性化学习路径
- 诊断你的SQL水平,生成定制学习计划
- 重点攻克薄弱环节,避免无效重复
- 追踪学习进度,可视化成长曲线
实战练习环境
- 在线SQL编辑器,支持多数据库
- 即时执行,查看结果
- 性能分析,理解执行计划
总结
SQL面试不难,但需要系统准备:
- 掌握核心语法:基础查询、JOIN、聚合函数、窗口函数
- 理解底层原理:索引、执行计划、查询优化
- 积累实战经验:真实场景、边界情况、性能调优
- 展示思维过程:理解需求、分析数据、解释思路
30道题只是起点,真正的提升来自持续练习和深度思考。祝你面试顺利,拿下心仪的Offer!
相关文章:
分享这篇文章:
本文由Interview AiBox团队原创,转载请注明出处。
Interview AiBoxInterview AiBox — 面试搭档
不只是准备,更是实时陪练
Interview AiBox 在面试过程中提供实时屏幕提示、AI 模拟面试和智能复盘,让你每一次回答都更有信心。
AI 助读
一键发送到常用 AI
智能总结
深度解读
考点定位
思路启发
分享文章
复制链接,或一键分享到常用平台