Interview AiBox logo

Interview AiBox 实时 AI 助手,让你自信应答每一场面试

立即体验 Interview AiBoxarrow_forward
7 分钟阅读Interview AiBox

SQL面试完全指南:30道高频题+标准答案解析

30道高频SQL面试题,覆盖基础查询、JOIN、聚合函数、窗口函数;每题含标准答案、解析和面试官视角,帮你把SQL从会写变成会讲。

  • sellSql
  • sellDatabase
  • sellInterview Questions
SQL面试完全指南:30道高频题+标准答案解析

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 NULLIS 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内连接

题目:有employeesdepartments两张表,查询每个员工的姓名及其部门名称。

答案

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 JOINLEFT 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)基本一致,差异主要在:

功能MySQLPostgreSQLSQL ServerOracle
字符串连接CONCAT()||+||
限制行数LIMITLIMITTOPFETCH FIRST
布尔类型
窗口函数8.0+支持完整支持完整支持完整支持
FULL JOIN不支持支持支持支持

面试时可以问清楚用哪个数据库,针对性回答。

Q4: 如何快速提升SQL能力?

A: 三步走:

  1. 系统学习语法:看官方文档或教程,建立完整知识体系
  2. 动手实践:在真实数据集上练习(Kaggle、政府公开数据)
  3. 分析慢查询:用EXPLAIN分析执行计划,理解索引原理

推荐资源:

Q5: 面试时手写SQL紧张怎么办?

A: 几个技巧:

  1. 先写伪代码:用中文描述逻辑,再翻译成SQL
  2. 分步写:先写主查询,再加JOIN、WHERE、GROUP BY
  3. 写完检查:语法、逻辑、边界情况
  4. 不会就说不会:诚实比瞎编好,可以说"这个语法我不太熟,但我知道思路是..."

Q6: SQL面试会考数据库设计吗?

A: 会,尤其是后端和数据岗位。常见问题:

  • 设计一个电商订单系统的表结构
  • 如何处理多对多关系?
  • 什么时候用外键?什么时候不用?
  • 如何设计索引?

建议学习基本的数据库设计原则:范式、反范式、索引设计。

Q7: 窗口函数这么重要,为什么很多人不会?

A: 两个原因:

  1. 历史原因:MySQL 8.0才支持窗口函数,很多教程和面试题还停留在旧版本
  2. 学习路径:很多人只学到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面试准备之旅免费试用Interview AiBox


总结

SQL面试不难,但需要系统准备:

  1. 掌握核心语法:基础查询、JOIN、聚合函数、窗口函数
  2. 理解底层原理:索引、执行计划、查询优化
  3. 积累实战经验:真实场景、边界情况、性能调优
  4. 展示思维过程:理解需求、分析数据、解释思路

30道题只是起点,真正的提升来自持续练习和深度思考。祝你面试顺利,拿下心仪的Offer!


相关文章

分享这篇文章


本文由Interview AiBox团队原创,转载请注明出处。

Interview AiBox logo

Interview AiBox — 面试搭档

不只是准备,更是实时陪练

Interview AiBox 在面试过程中提供实时屏幕提示、AI 模拟面试和智能复盘,让你每一次回答都更有信心。

分享文章

复制链接,或一键分享到常用平台

外部分享

阅读状态

阅读时长

7 分钟

阅读进度

2%

章节:57 · 已读:1

当前章节: sql面试完全指南30道高频题标准答案解析

最近更新:2026年3月10日

本页目录

Interview AiBox logo

Interview AiBox

AI 面试实时助手

面试中屏幕实时显示参考回答,帮你打磨表达。

立即体验arrow_forward

继续阅读

SQL面试完全指南:30道高频题+标准答案解析 | Interview AiBox