常见的SQL面试题:经典50例

常见的SQL面试题:经典50例

你是不是一听到"SQL面试题"就有点头皮发麻?别担心,今天我们就来一起抽丝剥茧,把这些看似复杂的题目一一攻克!作为一名工程师,我特别理解大家面对这些题目时的感受------就像拆解一台精密的机器,只要掌握了每个零件的功能,整台机器就能运转自如。

让我们先从最基础的零件开始吧!

SQL基础知识概述

想象一下,SQL就像是我们和数据库对话的"语言"。每一条SQL语句,都是在向数据库发出一个明确的指令。我们来看看这些"指令"都是什么意思:

  • SELECT :就像你告诉数据库:"嘿,我想要这些数据!"比如:[学号, 平均成绩: 组函数avg(成绩)]
  • FROM :告诉数据从哪儿来,就像去图书馆找书,先要知道在哪个书架。比如:[涉及到成绩: 成绩表score]
  • WHERE :设置筛选条件,就像在超市买东西时只挑打折的。比如:[b.课程号='0003' and b.成绩>80]
  • GROUP BY :把数据分组,就像把班级里的同学按身高分组。比如:[每个学生的平均: 按学号分组]
    • 小提示:在Oracle和SQL Server中,SELECT后面非分组的字段必须出现在GROUP BY后面,但在MySQL中比较灵活。
  • HAVING :对分组后的结果加条件,就像筛选出"身高超过1.8米的小组"。比如:[大于60分]
  • ORDER BY :排序,就像按成绩高低排座位。比如:[升序: 成绩 ASC / 降序: 成绩 DESC]
  • LIMIT :只取前N条记录,就像只拿排行榜前10名。比如:[limit 2 ==> 从0索引开始读取2个]
    • 注意:select * from table limit 2, 1; 表示跳过2条后取1条,也就是取第3条记录。

分组函数(Group Functions) 也是我们的好帮手:

  • 去重 DISTINCT()
  • 求和 SUM()
  • 计数 COUNT()
  • 平均值 AVG()
  • 最大值 MAX()
  • 最小值 MIN()

多表连接:就像拼图一样

当数据分散在多张表里时,我们需要把它们"连接"起来:

  • 内连接 (默认是INNER):JOIN ... ON ... --- 只取两张表都有的数据
  • 左连接LEFT JOIN tableName AS b ON a.key = b.key --- 左表全部保留,右表没有的用NULL填充
  • 右连接RIGHT JOIN --- 和左连接相反
  • UNION:并集(去重)
  • UNION ALL:并集(包含重复)
  • Oracle专属
    • INTERSECT:交集
    • MINUS (EXCEPT):差集

数据库对象:认识这些"工具"

  • 表(Table):存放数据的地方
  • 视图(View):存储的SELECT语句,就像给查询结果拍了个快照
  • 序列(Sequence):自动生成数字,常用于主键
  • 索引(Index):提升查询效率,就像书的目录
  • 同义词(Synonym):给表起个别名

视图实战

简单视图:

sql 复制代码
CREATE VIEW emp_vw AS
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id = 90;

查询视图:

sql 复制代码
SELECT * FROM emp_vw;

对简单视图可以进行DML操作:

sql 复制代码
UPDATE emp_vw
SET last_name = 'HelloKitty'
WHERE employee_id = 100;

复杂视图:

sql 复制代码
CREATE VIEW emp_vw2 AS
SELECT department_id, AVG(salary) avg_sal
FROM employees
GROUP BY department_id;

复杂视图不能进行DML操作,因为它涉及分组函数。

序列实战

sql 复制代码
CREATE SEQUENCE emp_seq1
START WITH 1
INCREMENT BY 1
MAXVALUE 10000
MINVALUE 1
CYCLE
NOCACHE;

查询当前值和下一个值:

sql 复制代码
SELECT emp_seq1.currval FROM dual;
SELECT emp_seq1.nextval FROM dual;

索引实战

Oracle会自动为具有唯一约束的列创建索引。我们也可以手动创建:

sql 复制代码
CREATE INDEX emp_idx ON emp2(name);
CREATE INDEX emp_idx2 ON emp2(id, name);

表的操作:DDL和DML

DDL(数据定义语言):创建、删除、修改表结构

  • CREATE TABLE ...
  • DROP TABLE ...
  • RENAME ... TO ...
  • TRUNCATE TABLE ...
  • ALTER TABLE ...

DML(数据操纵语言):操作数据

  • INSERT INTO ... VALUES ...
  • UPDATE ... SET ... WHERE ...
  • DELETE FROM ... WHERE ...

重要查询模板

掌握了这些基础,我们就可以组装出完整的查询语句了:

sql 复制代码
SELECT ...
GROUP FUNCTIONS (MIN()/MAX()/SUM()/AVG()/COUNT())
FROM ... JOIN ... ON ...
LEFT JOIN ... ON ... RIGHT JOIN ... ON ...
WHERE ...
GROUP BY ...
HAVING ...
ORDER BY ...
ASC / DESC
LIMIT (0,4)

常见SQL面试题:经典50题

现在,让我们进入最激动人心的部分!假设我们有4张表:

  • 学生表:student(学号, 学生姓名, 出生年月, 性别)
  • 成绩表:score(学号, 课程号, 成绩)
  • 课程表:course(课程号, 课程名称, 教师号)
  • 教师表:teacher(教师号, 教师姓名)

小建议:动手画一画这几张表的关系图,就像拼乐高前先看说明书,会让后面的工作事半功倍!

一、创建数据库和表

在Navicat中,我们先创建好这些表:

  1. 学生表:学号设为主键
  2. 成绩表:学号和课程号设为联合主键,成绩设为FLOAT类型
  3. 课程表:课程号设为主键
  4. 教师表:教师号设为主键,教师姓名允许为空

添加数据

sql 复制代码
-- 学生表
INSERT INTO student(学号, 姓名, 出生日期, 性别) VALUES ('0001', '猴子', '1989-01-01', '男');
INSERT INTO student(学号, 姓名, 出生日期, 性别) VALUES ('0002', '猴子', '1990-12-21', '女');

-- 成绩表
INSERT INTO score(学号, 课程号, 成绩) VALUES ('0001', '0001', 80);
INSERT INTO score(学号, 课程号, 成绩) VALUES ('0002', '0002', 60);

-- 课程表
INSERT INTO course(课程号, 课程名称, 教师号) VALUES ('0001', '语文', '0002');

-- 教师表
INSERT INTO teacher(教师号, 教师姓名) VALUES ('0001', '孟扎扎');

50道面试题分类解析

为了让你更容易消化,我把这50道题分成了几个类别。我们一起来逐个击破!

基础查询类

1. 查询姓"猴"的学生名单

2. 查询姓"孟"的老师人数

sql 复制代码
SELECT COUNT(教师号) FROM teacher WHERE 教师姓名 LIKE '孟%';
汇总统计分组分析

3. 查询课程编号为"0002"的总成绩

sql 复制代码
SELECT SUM(成绩) FROM score WHERE 课程号 = '0002';

4. 查询选修该课程的学生人数

sql 复制代码
SELECT COUNT(DISTINCT 学号) AS 学生人数 FROM score;

5. 查询每门课程的最高和最低分

sql 复制代码
SELECT 课程号, MAX(成绩) AS 最高分, MIN(成绩) AS 最低分 FROM score GROUP BY 课程号;

6. 查询男生、女生人数

sql 复制代码
SELECT 性别, COUNT(*) FROM student GROUP BY 性别;

7. 查询平均成绩大于60分的学生学号和平均成绩

sql 复制代码
SELECT 学号, AVG(成绩) FROM score GROUP BY 学号 HAVING AVG(成绩) > 60;

8. 查询至少选修两门课程的学生学号

sql 复制代码
SELECT 学号, COUNT(课程号) AS 选修课程数目 FROM score GROUP BY 学号 HAVING COUNT(课程号) >= 2;

9. 查询同名同性学生名单并统计同名人数

sql 复制代码
SELECT 姓名, COUNT(*) AS 人数 FROM student GROUP BY 姓名 HAVING COUNT(*) >= 2;

10. 查询不及格的课程并按课程号从大到小排列

sql 复制代码
SELECT 课程号 FROM score WHERE 成绩 < 60 ORDER BY 课程号 DESC;

11. 查询每门课程的平均成绩,并按平均成绩升序排序

sql 复制代码
SELECT 课程号, AVG(成绩) AS 平均成绩 FROM score GROUP BY 课程号 ORDER BY 平均成绩 ASC;

12. 查询课程编号为"0004"且分数小于60的学生学号

sql 复制代码
SELECT 学号 FROM score WHERE 课程号 = '0004' AND 成绩 < 60 ORDER BY 成绩 DESC;

13. 统计每门课程的选修人数(超过2人的课程才统计)

sql 复制代码
SELECT 课程号, COUNT(学号) AS '选修人数' FROM score GROUP BY 课程号 HAVING COUNT(学号) > 2 ORDER BY COUNT(学号) DESC, 课程号 ASC;

14. 查询两门以上不及格课程的同学的学号及其平均成绩

sql 复制代码
SELECT 学号, AVG(成绩) AS 平均成绩 FROM score WHERE 成绩 < 60 GROUP BY 学号 HAVING COUNT(课程号) >= 2;

15. 查询所有课程成绩小于60分学生的学号、姓名

sql 复制代码
SELECT 学号, 姓名 FROM student WHERE 学号 IN (SELECT 学号 FROM score WHERE 成绩 < 60);

16. 查询没有学全所有课的学生的学号、姓名

sql 复制代码
SELECT 学号, 姓名 FROM student WHERE 学号 IN (SELECT 学号 FROM score GROUP BY 学号 HAVING COUNT(课程号) < (SELECT COUNT(课程号) FROM course));

17. 查询只选修了两门课程的全部学生的学号和姓名

sql 复制代码
SELECT 学号, 姓名 FROM student WHERE 学号 IN (SELECT 学号 FROM score GROUP BY 学号 HAVING COUNT(课程号) = 2);

18. 查询1990年出生的学生名单

sql 复制代码
SELECT 学号, 姓名 FROM student WHERE YEAR(出生日期) = 1990;

19. 查询各科成绩前两名的记录

sql 复制代码
SELECT 课程号, MAX(成绩) AS 最大成绩 FROM score GROUP BY 课程号;

20. 查询所有学生的学号、姓名、选课数、总成绩

sql 复制代码
SELECT a.学号, a.姓名, COUNT(b.课程号) AS 选课数, SUM(b.成绩) AS 总成绩 FROM student AS a LEFT JOIN score AS b ON a.学号 = b.学号 GROUP BY a.学号;

21. 查询平均成绩大于85的所有学生的学号、姓名和平均成绩

sql 复制代码
SELECT a.学号, a.姓名, AVG(b.成绩) AS 平均成绩 FROM student AS a LEFT JOIN score AS b ON a.学号 = b.学号 GROUP BY a.学号 HAVING AVG(b.成绩) > 85;

22. 查询学生的选课情况:学号,姓名,课程号,课程名称

sql 复制代码
SELECT a.学号, a.姓名, c.课程号, c.课程名称 FROM student a INNER JOIN score b ON a.学号 = b.学号 INNER JOIN course c ON b.课程号 = c.课程号;

23. 查询出每门课程的及格人数和不及格人数

sql 复制代码
SELECT 课程号, SUM(CASE WHEN 成绩 >= 60 THEN 1 ELSE 0 END) AS 及格人数, SUM(CASE WHEN 成绩 < 60 THEN 1 ELSE 0 END) AS 不及格人数 FROM score GROUP BY 课程号;

24. 使用分段统计各科成绩,分别统计各分数段人数,课程号和课程名称

sql 复制代码
SELECT a.课程号, b.课程名称, SUM(CASE WHEN 成绩 BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS '[100-85]', SUM(CASE WHEN 成绩 >= 70 AND 成绩 < 85 THEN 1 ELSE 0 END) AS '[85-70]', SUM(CASE WHEN 成绩 >= 60 AND 成绩 < 70 THEN 1 ELSE 0 END) AS '[70-60]', SUM(CASE WHEN 成绩 < 60 THEN 1 ELSE 0 END) AS '[<60]' FROM score AS a RIGHT JOIN course AS b ON a.课程号 = b.课程号 GROUP BY a.课程号, b.课程名称;

25. 查询课程编号为0003且课程成绩在80分以上的学生的学号和姓名

sql 复制代码
SELECT a.学号, a.姓名 FROM student AS a INNER JOIN score AS b ON a.学号 = b.学号 WHERE b.课程号 = '0003' AND b.成绩 > 80;

26. 使用SQL实现将成绩表行转列

sql 复制代码
SELECT 学号, MAX(CASE 课程号 WHEN '0001' THEN 成绩 ELSE 0 END) AS '课程号0001', MAX(CASE 课程号 WHEN '0002' THEN 成绩 ELSE 0 END) AS '课程号0002', MAX(CASE 课程号 WHEN '0003' THEN 成绩 ELSE 0 END) AS '课程号0003' FROM score GROUP BY 学号;

总结

看到这里,你是不是觉得SQL面试题其实也没那么可怕?其实,常见的面试题主要考察的就是分组取每组最大值、最小值 以及每组最大的N条记录这些核心技能。

就像我们工程师常说的:手中有剑,心里不慌!掌握了这些基础,再遇到类似的题目,你就能像庖丁解牛一样,游刃有余。

如果你觉得这篇文章对你有帮助,不妨花上20分钟,跟着我的思路,把上面的题目亲手写一遍。相信我,当你亲手跑通每一条SQL的时候,那种成就感会让你爱上这个过程的!

加油,未来的SQL大师!🚀


学SQL,光看不练可不行!🔥

超全SQL学习资源来啦:资料+练习+视频一步到位!推荐自学神器👉 SQL自学网 http://xuesql.cn

零基础也能轻松上手,还有入门好站:https://www.w3schools.com

赶紧动起手来,边练边学效率翻倍!🚀

相关推荐
可乐奶茶sky7 小时前
MonoGS 源码学习
学习
硅徒7 小时前
金融系统渗透测试复盘:从授权边界到报告整改的全流程
人工智能
学术小白人7 小时前
【倒计时4个月】-AI赋能图像处理与计算机视觉技术国际学术研讨会
网络·人工智能·神经网络·数据分析·光学
俊哥V7 小时前
每日 AI 研究简报 · 2026-07-20
人工智能·ai
炘爚7 小时前
Inkling模型调研
人工智能
谜之锋7 小时前
银河麒麟 Debian 系统离线deb包安装Mariadb 数据库指南
数据库·debian·mariadb
SLD_Allen7 小时前
AI Agent可观测性:破解多步推理的“黑盒”困局
人工智能·可用性测试·观测
薛定谔的猫19827 小时前
Llama-Factory微调 Qwen2.5-3B 模型 合并与导出(二)
人工智能·llama-factory微调
kongba0077 小时前
《Prompting》使用经验逐条总结
人工智能