常见的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

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

相关推荐
博图光电4 分钟前
Libra 27105相关技术参数
人工智能·数码相机
Titan202414 分钟前
MySQL访问个人学习笔记
笔记·学习·mysql
IT_陈寒29 分钟前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
yumgpkpm42 分钟前
Acceldata ODP(Open Data Platform)3.3.6.4(RHEL9)保姆级完整安装手册
大数据·人工智能·hive·hadoop·kafka·hbase·cloudera
程序员cxuan1 小时前
腾讯又来一王炸,开源版 WorkBuddy 太夯了!
人工智能·后端·程序员
邓工说电1 小时前
智慧断路器安全吗?数据加密、离线保护与合规认证全解读
大数据·数据库·人工智能·智能断路器·炜晔科技
阿里云大数据AI技术1 小时前
Lance 数据检索怎么选,当然阿里云 Milvus 向量湖
人工智能
出海客1 小时前
跨境电商多语言客服知识库怎么建:资料结构、检索边界与人工升级
大数据·人工智能
adinnet20261 小时前
企业微调大模型(Fine-tuning):先吃透 RAG 还是先训自己的模型
大数据·数据库
xsd202411181 小时前
从自主导航到视觉读表:一台工业巡检机器人的全栈技术链路拆解
人工智能