首页 > 数据库 > MySQL > 常见的SQL面试题:经典50例
你是不是一听到“SQL面试题”就有点头皮发麻?别担心,今天我们就来一起抽丝剥茧,把这些看似复杂的题目一一攻克!作为一名工程师,我特别理解大家面对这些题目时的感受——就像拆解一台精密的机器,只要掌握了每个零件的功能,整台机器就能运转自如。
让我们先从最基础的零件开始吧!

想象一下,SQL就像是我们和数据库对话的“语言”。每一条SQL语句,都是在向数据库发出一个明确的指令。我们来看看这些“指令”都是什么意思:
[学号, 平均成绩: 组函数avg(成绩)][涉及到成绩: 成绩表score][b.课程号='0003' and b.成绩>80][每个学生的平均: 按学号分组][大于60分][升序: 成绩 ASC / 降序: 成绩 DESC][limit 2 ==> 从0索引开始读取2个]select * from table limit 2, 1; 表示跳过2条后取1条,也就是取第3条记录。分组函数(Group Functions) 也是我们的好帮手:
DISTINCT()SUM()COUNT()AVG()MAX()MIN()当数据分散在多张表里时,我们需要把它们“连接”起来:
JOIN ... ON ... — 只取两张表都有的数据LEFT JOIN tableName AS b ON a.key = b.key — 左表全部保留,右表没有的用NULL填充RIGHT JOIN — 和左连接相反INTERSECT:交集MINUS (EXCEPT):差集简单视图:
CREATE VIEW emp_vw AS SELECT employee_id, last_name, salary FROM employees WHERE department_id = 90;
查询视图:
SELECT * FROM emp_vw;
对简单视图可以进行DML操作:
UPDATE emp_vw SET last_name = 'HelloKitty' WHERE employee_id = 100;
复杂视图:
CREATE VIEW emp_vw2 AS SELECT department_id, AVG(salary) avg_sal FROM employees GROUP BY department_id;
复杂视图不能进行DML操作,因为它涉及分组函数。
CREATE SEQUENCE emp_seq1 START WITH 1 INCREMENT BY 1 MAXVALUE 10000 MINVALUE 1 CYCLE NOCACHE;
查询当前值和下一个值:
SELECT emp_seq1.currval FROM dual; SELECT emp_seq1.nextval FROM dual;
Oracle会自动为具有唯一约束的列创建索引。我们也可以手动创建:
CREATE INDEX emp_idx ON emp2(name); CREATE INDEX emp_idx2 ON emp2(id, name);
DDL(数据定义语言):创建、删除、修改表结构
CREATE TABLE ...DROP TABLE ...RENAME ... TO ...TRUNCATE TABLE ...ALTER TABLE ...DML(数据操纵语言):操作数据
INSERT INTO ... VALUES ...UPDATE ... SET ... WHERE ...DELETE FROM ... WHERE ...掌握了这些基础,我们就可以组装出完整的查询语句了:
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)
现在,让我们进入最激动人心的部分!假设我们有4张表:
小建议:动手画一画这几张表的关系图,就像拼乐高前先看说明书,会让后面的工作事半功倍!
在Navicat中,我们先创建好这些表:
-- 学生表
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道题分成了几个类别。我们一起来逐个击破!
1. 查询姓“猴”的学生名单 2. 查询姓“孟”的老师人数
SELECT COUNT(教师号) FROM teacher WHERE 教师姓名 LIKE '孟%';
3. 查询课程编号为“0002”的总成绩
SELECT SUM(成绩) FROM score WHERE 课程号 = '0002';
4. 查询选修该课程的学生人数
SELECT COUNT(DISTINCT 学号) AS 学生人数 FROM score;
5. 查询每门课程的最高和最低分
SELECT 课程号, MAX(成绩) AS 最高分, MIN(成绩) AS 最低分 FROM score GROUP BY 课程号;
6. 查询男生、女生人数
SELECT 性别, COUNT(*) FROM student GROUP BY 性别;
7. 查询平均成绩大于60分的学生学号和平均成绩
SELECT 学号, AVG(成绩) FROM score GROUP BY 学号 HAVING AVG(成绩) > 60;
8. 查询至少选修两门课程的学生学号
SELECT 学号, COUNT(课程号) AS 选修课程数目 FROM score GROUP BY 学号 HAVING COUNT(课程号) >= 2;
9. 查询同名同性学生名单并统计同名人数
SELECT 姓名, COUNT(*) AS 人数 FROM student GROUP BY 姓名 HAVING COUNT(*) >= 2;
10. 查询不及格的课程并按课程号从大到小排列
SELECT 课程号 FROM score WHERE 成绩 < 60 ORDER BY 课程号 DESC;
11. 查询每门课程的平均成绩,并按平均成绩升序排序
SELECT 课程号, AVG(成绩) AS 平均成绩 FROM score GROUP BY 课程号 ORDER BY 平均成绩 ASC;
12. 查询课程编号为“0004”且分数小于60的学生学号
SELECT 学号 FROM score WHERE 课程号 = '0004' AND 成绩 < 60 ORDER BY 成绩 DESC;
13. 统计每门课程的选修人数(超过2人的课程才统计)
SELECT 课程号, COUNT(学号) AS '选修人数' FROM score GROUP BY 课程号 HAVING COUNT(学号) > 2 ORDER BY COUNT(学号) DESC, 课程号 ASC;
14. 查询两门以上不及格课程的同学的学号及其平均成绩
SELECT 学号, AVG(成绩) AS 平均成绩 FROM score WHERE 成绩 < 60 GROUP BY 学号 HAVING COUNT(课程号) >= 2;
15. 查询所有课程成绩小于60分学生的学号、姓名
SELECT 学号, 姓名 FROM student WHERE 学号 IN (SELECT 学号 FROM score WHERE 成绩 < 60);
16. 查询没有学全所有课的学生的学号、姓名
SELECT 学号, 姓名 FROM student WHERE 学号 IN (SELECT 学号 FROM score GROUP BY 学号 HAVING COUNT(课程号) < (SELECT COUNT(课程号) FROM course));
17. 查询只选修了两门课程的全部学生的学号和姓名
SELECT 学号, 姓名 FROM student WHERE 学号 IN (SELECT 学号 FROM score GROUP BY 学号 HAVING COUNT(课程号) = 2);
18. 查询1990年出生的学生名单
SELECT 学号, 姓名 FROM student WHERE YEAR(出生日期) = 1990;
19. 查询各科成绩前两名的记录
SELECT 课程号, MAX(成绩) AS 最大成绩 FROM score GROUP BY 课程号;
20. 查询所有学生的学号、姓名、选课数、总成绩
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的所有学生的学号、姓名和平均成绩
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. 查询学生的选课情况:学号,姓名,课程号,课程名称
SELECT a.学号, a.姓名, c.课程号, c.课程名称 FROM student a INNER JOIN score b ON a.学号 = b.学号 INNER JOIN course c ON b.课程号 = c.课程号;
23. 查询出每门课程的及格人数和不及格人数
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. 使用分段统计各科成绩,分别统计各分数段人数,课程号和课程名称
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分以上的学生的学号和姓名
SELECT a.学号, a.姓名 FROM student AS a INNER JOIN score AS b ON a.学号 = b.学号 WHERE b.课程号 = '0003' AND b.成绩 > 80;
26. 使用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 赶紧动起手来,边练边学效率翻倍!🚀
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70049428/viewspace-3176246/ ,如需转载,请注明出处,否则将追究法律责任。