MySQL 经典练习 50 题(完美解答版,提供解题思路)
MySQL 经典练习 50 题(完美解答版)
- MySQL 经典练习 50 题(完美解答版)
- 一、数据库与表设计
- 1. 创建数据库
- 2. 创建表结构
- (1)学生表(student)
- (2)课程表(course)
- (3)教师表(teacher)
- (4)成绩表(score)
- 3. 表关系说明
- 二、插入样例数据
- 三、经典练习50题及解答
- 1. 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
- 2. 查询"01"课程比"02"课程成绩低的学生的信息及课程分数
- 3. 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
- 4. 查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩(包括有成绩的和无成绩的)
- 5. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
- 6. 查询"李"姓老师的数量
- 7. 查询学过"张三"老师授课的同学的信息
- 8. 查询没学过"张三"老师授课的同学的信息
- 9. 查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
- 10. 查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
- 11. 查询没有学全所有课程的同学的信息
- 12. 查询至少有一门课与学号为"01"的同学所学相同的同学的信息
- 13. 查询和"01"号的同学学习的课程完全相同的其他同学的信息
- 14. 查询没学过"张三"老师讲授的任一门课程的学生姓名
- 15. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
- 16. 检索"01"课程分数小于60,按分数降序排列的学生信息
- 17. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
- 18. 查询各科成绩最高分、最低分和平均分,以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
- 19. 按各科成绩进行排序,并显示排名
- 20. 查询学生的总成绩并进行排名
- 21. 查询不同老师所教不同课程平均分从高到低显示
- 22. 查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
- 23. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
- 24. 查询学生平均成绩及其名次
- 25. 查询各科成绩前三名的记录
- 26. 查询每门课程被选修的学生数
- 27. 查询出只有两门课程的全部学生的学号和姓名
- 28. 查询男生、女生人数
- 29. 查询名字中含有"风"字的学生信息
- 30. 查询同名同性学生名单,并统计同名人数
- 31. 查询1990年出生的学生名单
- 32. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
- 33. 查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
- 34. 查询课程名称为"数学",且分数低于60的学生姓名和分数
- 35. 查询所有学生的课程及分数情况(即学生-课程成绩矩阵)
- 36. 查询任何一门课程成绩在70分以上的学生姓名、课程名称和分数
- 37. 查询课程不及格的学生
- 38. 查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
- 39. 求每门课程的学生人数
- 40. 查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
- 41. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
- 42. 查询每门课程成绩最好的前三名
- 43. 统计每门课程的学生选修人数(超过5人的课程才统计)
- 44. 检索至少选修两门课程的学生学号
- 45. 查询选修了全部课程的学生信息
- 46. 查询各学生的年龄(周岁)
- 47. 查询本周过生日的学生
- 48. 查询下周过生日的学生
- 49. 查询本月过生日的学生
- 50. 查询12月份过生日的学生
一、数据库与表设计
为完成以下练习,我们需要创建一个包含学生、课程、教师、成绩信息的数据库,以及对应的4张表。
1. 创建数据库
首先创建名为 school
的数据库:
CREATE DATABASE IF NOT EXISTS school;
USE school;
2. 创建表结构
(1)学生表(student)
存储学生的基本信息,包括学号、姓名、性别、出生年月。
CREATE TABLE IF NOT EXISTS student (s_id VARCHAR(20) PRIMARY KEY, -- 学生编号s_name VARCHAR(20) NOT NULL, -- 学生姓名s_sex VARCHAR(10) NOT NULL, -- 性别(男/女)s_birth DATE NOT NULL -- 出生年月
);
(2)课程表(course)
存储课程信息,包括课程编号、课程名、授课教师编号。
CREATE TABLE IF NOT EXISTS course (c_id VARCHAR(20) PRIMARY KEY, -- 课程编号c_name VARCHAR(20) NOT NULL, -- 课程名称t_id VARCHAR(20) NOT NULL -- 教师编号(关联教师表)
);
(3)教师表(teacher)
存储教师信息,包括教师编号、教师姓名。
CREATE TABLE IF NOT EXISTS teacher (t_id VARCHAR(20) PRIMARY KEY, -- 教师编号t_name VARCHAR(20) NOT NULL -- 教师姓名
);
(4)成绩表(score)
存储学生的课程成绩,包括学号、课程编号、成绩(可空,代表未选课或未考试)。
CREATE TABLE IF NOT EXISTS score (s_id VARCHAR(20) NOT NULL, -- 学生编号(关联学生表)c_id VARCHAR(20) NOT NULL, -- 课程编号(关联课程表)s_score DECIMAL(5,2), -- 成绩(保留2位小数)PRIMARY KEY (s_id, c_id) -- 联合主键(一个学生一门课只有一个成绩)
);
3. 表关系说明
- 学生表(student)与成绩表(score):一对多关系(一个学生可有多门课成绩),通过
s_id
关联。 - 课程表(course)与成绩表(score):一对多关系(一门课程可有多个学生成绩),通过
c_id
关联。 - 教师表(teacher)与课程表(course):一对多关系(一个教师可教多门课程),通过
t_id
关联。
二、插入样例数据
为方便练习,我们插入以下样例数据(覆盖不同场景:成绩高低、及格/不及格、同名学生、不同性别等)。
-- 插入学生数据
INSERT INTO student VALUES
('01', '赵雷', '男', '1990-01-01'),
('02', '钱电', '男', '1990-12-21'),
('03', '孙风', '女', '1990-05-20'),
('04', '李云', '女', '1990-08-06'),
('05', '周梅', '女', '1991-12-01'),
('06', '吴兰', '女', '1992-03-01'),
('07', '郑竹', '男', '1989-07-01'),
('08', '王菊', '女', '1990-01-20'),
('09', '赵雷', '男', '1990-02-01'); -- 同名同性学生-- 插入教师数据
INSERT INTO teacher VALUES
('01', '张三'),
('02', '李四'),
('03', '王五');-- 插入课程数据(关联教师)
INSERT INTO course VALUES
('01', '语文', '02'), -- 李四教语文
('02', '数学', '01'), -- 张三教数学
('03', '英语', '03'), -- 王五教英语
('04', '物理', '01'); -- 张三教物理-- 插入成绩数据(包含不及格、NULL(未选课)等情况)
INSERT INTO score VALUES
('01', '01', 80), -- 赵雷-语文-80
('01', '02', 90), -- 赵雷-数学-90
('01', '03', 99), -- 赵雷-英语-99
('02', '01', 70), -- 钱电-语文-70
('02', '02', 60), -- 钱电-数学-60
('02', '03', 80), -- 钱电-英语-80
('03', '01', 80), -- 孙风-语文-80
('03', '02', 80), -- 孙风-数学-80
('03', '03', 80), -- 孙风-英语-80
('04', '01', 50), -- 李云-语文-50(不及格)
('04', '02', 30), -- 李云-数学-30(不及格)
('05', '01', 90), -- 周梅-语文-90
('05', '02', 90), -- 周梅-数学-90
('06', '03', 50), -- 吴兰-英语-50(不及格)
('07', '02', 100), -- 郑竹-数学-100
('07', '04', 80), -- 郑竹-物理-80
('08', '03', 90), -- 王菊-英语-90
('09', '02', 60); -- 赵雷(同名)-数学-60
三、经典练习50题及解答
1. 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
思路:通过成绩表自连接,分别获取学生的01课程和02课程成绩,再关联学生表筛选符合条件的记录。
SELECT s.*, sc1.s_score AS '01课程分数', sc2.s_score AS '02课程分数'
FROM student s
JOIN score sc1 ON s.s_id = sc1.s_id AND sc1.c_id = '01' -- 01课程成绩
JOIN score sc2 ON s.s_id = sc2.s_id AND sc2.c_id = '02' -- 02课程成绩
WHERE sc1.s_score > sc2.s_score;
2. 查询"01"课程比"02"课程成绩低的学生的信息及课程分数
思路:与第1题类似,仅条件改为01课程成绩 < 02课程成绩。
SELECT s.*, sc1.s_score AS '01课程分数', sc2.s_score AS '02课程分数'
FROM student s
JOIN score sc1 ON s.s_id = sc1.s_id AND sc1.c_id = '01'
JOIN score sc2 ON s.s_id = sc2.s_id AND sc2.c_id = '02'
WHERE sc1.s_score < sc2.s_score;
3. 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
思路:按学生分组计算平均成绩,用HAVING
筛选平均成绩≥60的记录。
SELECT s.s_id, s.s_name, AVG(sc.s_score) AS 平均成绩
FROM student s
JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name
HAVING 平均成绩 >= 60;
4. 查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩(包括有成绩的和无成绩的)
思路:用左连接保留所有学生(包括无成绩的),用IFNULL
将NULL成绩转为0,再筛选平均成绩<60的记录。
SELECT s.s_id, s.s_name, AVG(IFNULL(sc.s_score, 0)) AS 平均成绩 -- 无成绩按0计算
FROM student s
LEFT JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name
HAVING 平均成绩 < 60;
5. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
思路:按学生分组,用COUNT
统计选课数(排除NULL),用SUM
计算总成绩(NULL按0处理)。
SELECT s.s_id, s.s_name, COUNT(sc.c_id) AS 选课总数, -- 统计选课数(NULL不计数)SUM(IFNULL(sc.s_score, 0)) AS 总成绩 -- 无成绩按0计算
FROM student s
LEFT JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name;
6. 查询"李"姓老师的数量
思路:用LIKE
匹配姓氏为“李”的教师,统计数量。
SELECT COUNT(t_id) AS 李姓老师数量
FROM teacher
WHERE t_name LIKE '李%';
7. 查询学过"张三"老师授课的同学的信息
思路:通过教师表→课程表→成绩表关联,筛选张三教的课程对应的学生。
SELECT DISTINCT s.* -- 去重(避免同一学生选多门张三的课)
FROM student s
JOIN score sc ON s.s_id = sc.s_id
JOIN course c ON sc.c_id = c.c_id
JOIN teacher t ON c.t_id = t.t_id
WHERE t.t_name = '张三';
8. 查询没学过"张三"老师授课的同学的信息
思路:先找到学过张三课程的学生ID,再用NOT IN
筛选不在其中的学生。
SELECT *
FROM student
WHERE s_id NOT IN (SELECT DISTINCT sc.s_idFROM score scJOIN course c ON sc.c_id = c.c_idJOIN teacher t ON c.t_id = t.t_idWHERE t.t_name = '张三'
);
9. 查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
思路:用成绩表自连接,筛选同时有01和02课程成绩的学生。
SELECT s.*
FROM student s
JOIN score sc1 ON s.s_id = sc1.s_id AND sc1.c_id = '01'
JOIN score sc2 ON s.s_id = sc2.s_id AND sc2.c_id = '02';
10. 查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
思路:先找到学过01课程的学生,再排除学过02课程的学生。
SELECT s.*
FROM student s
JOIN score sc1 ON s.s_id = sc1.s_id AND sc1.c_id = '01'
LEFT JOIN score sc2 ON s.s_id = sc2.s_id AND sc2.c_id = '02'
WHERE sc2.s_id IS NULL; -- 没有02课程成绩
11. 查询没有学全所有课程的同学的信息
思路:先统计总课程数,再筛选选课数小于总课程数的学生。
-- 总课程数
SET @total_course = (SELECT COUNT(*) FROM course);SELECT s.*
FROM student s
LEFT JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name
HAVING COUNT(DISTINCT sc.c_id) < @total_course;
12. 查询至少有一门课与学号为"01"的同学所学相同的同学的信息
思路:先找到01号学生学过的课程,再筛选学过这些课程的其他学生。
SELECT DISTINCT s.*
FROM student s
JOIN score sc ON s.s_id = sc.s_id
WHERE sc.c_id IN (SELECT c_id FROM score WHERE s_id = '01' -- 01号学生学过的课程
) AND s.s_id != '01'; -- 排除01号自身
13. 查询和"01"号的同学学习的课程完全相同的其他同学的信息
思路:筛选与01号学生选课数量相同,且所有课程都重合的学生。
-- 01号学生的选课数
SET @01_course_count = (SELECT COUNT(*) FROM score WHERE s_id = '01');SELECT s.*
FROM student s
WHERE s.s_id != '01' -- 排除01号自身
AND (SELECT COUNT(*) FROM score WHERE s_id = s.s_id) = @01_course_count -- 选课数相同
AND NOT EXISTS (-- 不存在01号学过但该学生没学过的课程SELECT c_id FROM score WHERE s_id = '01'EXCEPTSELECT c_id FROM score WHERE s_id = s.s_id
);
14. 查询没学过"张三"老师讲授的任一门课程的学生姓名
思路:先找到张三教的课程,再筛选没学过这些课程的学生。
SELECT s_name
FROM student
WHERE s_id NOT IN (SELECT DISTINCT sc.s_idFROM score scJOIN course c ON sc.c_id = c.c_idJOIN teacher t ON c.t_id = t.t_idWHERE t.t_name = '张三'
);
15. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
思路:筛选成绩<60的记录,按学生分组统计不及格课程数≥2,再计算平均成绩。
SELECT s.s_id, s.s_name, AVG(sc.s_score) AS 平均成绩
FROM student s
JOIN score sc ON s.s_id = sc.s_id
WHERE sc.s_score < 60 -- 仅统计不及格成绩
GROUP BY s.s_id, s.s_name
HAVING COUNT(sc.c_id) >= 2; -- 不及格课程≥2门
16. 检索"01"课程分数小于60,按分数降序排列的学生信息
思路:筛选01课程且成绩<60的记录,按分数降序排序。
SELECT s.*, sc.s_score
FROM student s
JOIN score sc ON s.s_id = sc.s_id
WHERE sc.c_id = '01' AND sc.s_score < 60
ORDER BY sc.s_score DESC;
17. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
思路:用窗口函数AVG()
计算每个学生的平均成绩(无需分组),按平均成绩排序。
SELECT s.s_id, s.s_name, sc.c_id, sc.s_score,AVG(sc.s_score) OVER (PARTITION BY s.s_id) AS 平均成绩 -- 按学生分组计算平均
FROM student s
LEFT JOIN score sc ON s.s_id = sc.s_id
ORDER BY 平均成绩 DESC;
18. 查询各科成绩最高分、最低分和平均分,以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
(注:及格≥60,中等≥70,优良≥80,优秀≥90)
SELECT c.c_id,c.c_name,MAX(sc.s_score) AS 最高分,MIN(sc.s_score) AS 最低分,AVG(sc.s_score) AS 平均分,-- 及格率(≥60)ROUND(SUM(CASE WHEN sc.s_score >= 60 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS 及格率(%),-- 中等率(≥70)ROUND(SUM(CASE WHEN sc.s_score >= 70 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS 中等率(%),-- 优良率(≥80)ROUND(SUM(CASE WHEN sc.s_score >= 80 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS 优良率(%),-- 优秀率(≥90)ROUND(SUM(CASE WHEN sc.s_score >= 90 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS 优秀率(%)
FROM course c
JOIN score sc ON c.c_id = sc.c_id
GROUP BY c.c_id, c.c_name;
19. 按各科成绩进行排序,并显示排名
思路:用窗口函数RANK()
按课程分组排序(相同成绩排名相同,后续排名跳空)。
SELECT sc.s_id,sc.c_id,sc.s_score,RANK() OVER (PARTITION BY sc.c_id ORDER BY sc.s_score DESC) AS 排名
FROM score sc;
20. 查询学生的总成绩并进行排名
思路:先计算每个学生的总成绩,再用RANK()
排名。
SELECT s_id,总成绩,RANK() OVER (ORDER BY 总成绩 DESC) AS 排名
FROM (SELECT s_id, SUM(s_score) AS 总成绩 FROM score GROUP BY s_id
) AS total;
21. 查询不同老师所教不同课程平均分从高到低显示
思路:关联教师、课程、成绩表,按教师和课程分组计算平均分,按平均分降序排序。
SELECT t.t_id,t.t_name,c.c_id,c.c_name,AVG(sc.s_score) AS 平均分
FROM teacher t
JOIN course c ON t.t_id = c.t_id
JOIN score sc ON c.c_id = sc.c_id
GROUP BY t.t_id, t.t_name, c.c_id, c.c_name
ORDER BY 平均分 DESC;
22. 查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
思路:用窗口函数RANK()
获取各科排名,再筛选排名为2或3的记录。
SELECT s.s_id,s.s_name,r.c_id,r.s_score,r.排名
FROM (SELECT sc.*,RANK() OVER (PARTITION BY sc.c_id ORDER BY sc.s_score DESC) AS 排名FROM score sc
) AS r
JOIN student s ON r.s_id = s.s_id
WHERE r.排名 BETWEEN 2 AND 3;
23. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
SELECT c.c_id,c.c_name,-- 100-85分人数及百分比SUM(CASE WHEN sc.s_score BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS '[100-85]',ROUND(SUM(CASE WHEN sc.s_score BETWEEN 85 AND 100 THEN 1 ELSE 0 END)/COUNT(*)*100,2) AS '[100-85]%',-- 85-70分人数及百分比SUM(CASE WHEN sc.s_score BETWEEN 70 AND 84 THEN 1 ELSE 0 END) AS '[85-70]',ROUND(SUM(CASE WHEN sc.s_score BETWEEN 70 AND 84 THEN 1 ELSE 0 END)/COUNT(*)*100,2) AS '[85-70]%',-- 70-60分人数及百分比SUM(CASE WHEN sc.s_score BETWEEN 60 AND 69 THEN 1 ELSE 0 END) AS '[70-60]',ROUND(SUM(CASE WHEN sc.s_score BETWEEN 60 AND 69 THEN 1 ELSE 0 END)/COUNT(*)*100,2) AS '[70-60]%',-- 0-60分人数及百分比SUM(CASE WHEN sc.s_score < 60 THEN 1 ELSE 0 END) AS '[0-60]',ROUND(SUM(CASE WHEN sc.s_score < 60 THEN 1 ELSE 0 END)/COUNT(*)*100,2) AS '[0-60]%'
FROM course c
JOIN score sc ON c.c_id = sc.c_id
GROUP BY c.c_id, c.c_name;
24. 查询学生平均成绩及其名次
思路:计算每个学生的平均成绩,用RANK()
排名。
SELECT s_id,平均成绩,RANK() OVER (ORDER BY 平均成绩 DESC) AS 名次
FROM (SELECT s_id, AVG(s_score) AS 平均成绩 FROM score GROUP BY s_id
) AS avg_score;
25. 查询各科成绩前三名的记录
思路:用窗口函数ROW_NUMBER()
按课程分组排序,取前3名(若有并列成绩,ROW_NUMBER会强制排序,RANK可能返回更多)。
SELECT c_id,s_id,s_score,排名
FROM (SELECT *,ROW_NUMBER() OVER (PARTITION BY c_id ORDER BY s_score DESC) AS 排名FROM score
) AS r
WHERE 排名 <= 3;
26. 查询每门课程被选修的学生数
思路:按课程分组,统计学生数(去重,避免同一学生重复计数)。
SELECT c_id, COUNT(DISTINCT s_id) AS 选修学生数
FROM score
GROUP BY c_id;
27. 查询出只有两门课程的全部学生的学号和姓名
思路:按学生分组,统计选课数=2的学生。
SELECT s.s_id, s.s_name
FROM student s
JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name
HAVING COUNT(sc.c_id) = 2;
28. 查询男生、女生人数
思路:按性别分组统计人数。
SELECT s_sex, COUNT(s_id) AS 人数
FROM student
GROUP BY s_sex;
29. 查询名字中含有"风"字的学生信息
思路:用LIKE
匹配包含“风”的姓名。
SELECT *
FROM student
WHERE s_name LIKE '%风%';
30. 查询同名同性学生名单,并统计同名人数
思路:按姓名和性别分组,筛选人数>1的组。
SELECT s_name, s_sex, COUNT(*) AS 同名人数
FROM student
GROUP BY s_name, s_sex
HAVING COUNT(*) > 1;
31. 查询1990年出生的学生名单
思路:用YEAR()
函数提取出生年份,筛选=1990的记录。
SELECT *
FROM student
WHERE YEAR(s_birth) = 1990;
32. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
思路:按课程分组计算平均分,用ORDER BY
指定排序规则。
SELECT c_id, AVG(s_score) AS 平均成绩
FROM score
GROUP BY c_id
ORDER BY 平均成绩 DESC, c_id ASC;
33. 查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
思路:按学生分组计算平均分,筛选≥85的记录。
SELECT s.s_id, s.s_name, AVG(sc.s_score) AS 平均成绩
FROM student s
JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name
HAVING 平均成绩 >= 85;
34. 查询课程名称为"数学",且分数低于60的学生姓名和分数
思路:关联课程表和成绩表,筛选课程名为“数学”且成绩<60的记录。
SELECT s.s_name, sc.s_score
FROM student s
JOIN score sc ON s.s_id = sc.s_id
JOIN course c ON sc.c_id = c.c_id
WHERE c.c_name = '数学' AND sc.s_score < 60;
35. 查询所有学生的课程及分数情况(即学生-课程成绩矩阵)
思路:用CASE WHEN
将课程成绩转为列(适合课程数量固定的场景)。
SELECT s.s_id,s.s_name,MAX(CASE WHEN c.c_name = '语文' THEN sc.s_score END) AS 语文,MAX(CASE WHEN c.c_name = '数学' THEN sc.s_score END) AS 数学,MAX(CASE WHEN c.c_name = '英语' THEN sc.s_score END) AS 英语,MAX(CASE WHEN c.c_name = '物理' THEN sc.s_score END) AS 物理
FROM student s
LEFT JOIN score sc ON s.s_id = sc.s_id
LEFT JOIN course c ON sc.c_id = c.c_id
GROUP BY s.s_id, s.s_name;
36. 查询任何一门课程成绩在70分以上的学生姓名、课程名称和分数
思路:直接筛选成绩>70的记录,关联学生和课程表。
SELECT s.s_name, c.c_name, sc.s_score
FROM student s
JOIN score sc ON s.s_id = sc.s_id
JOIN course c ON sc.c_id = c.c_id
WHERE sc.s_score > 70;
37. 查询课程不及格的学生
思路:筛选成绩<60的记录,关联学生和课程表。
SELECT s.s_id, s.s_name, c.c_name, sc.s_score
FROM student s
JOIN score sc ON s.s_id = sc.s_id
JOIN course c ON sc.c_id = c.c_id
WHERE sc.s_score < 60;
38. 查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
思路:筛选课程01且成绩>80的记录,关联学生表。
SELECT s.s_id, s.s_name
FROM student s
JOIN score sc ON s.s_id = sc.s_id
WHERE sc.c_id = '01' AND sc.s_score > 80;
39. 求每门课程的学生人数
思路:与第26题相同,按课程分组统计学生数。
SELECT c_id, COUNT(DISTINCT s_id) AS 学生人数
FROM score
GROUP BY c_id;
40. 查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
思路:先找到张三教的课程,再筛选这些课程中成绩最高的记录。
SELECT s.*, sc.s_score, c.c_name
FROM student s
JOIN score sc ON s.s_id = sc.s_id
JOIN course c ON sc.c_id = c.c_id
JOIN teacher t ON c.t_id = t.t_id
WHERE t.t_name = '张三'
AND sc.s_score = (-- 张三所授课程的最高成绩SELECT MAX(sc2.s_score)FROM score sc2JOIN course c2 ON sc2.c_id = c2.c_idJOIN teacher t2 ON c2.t_id = t2.t_idWHERE t2.t_name = '张三'
);
41. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
思路:成绩表自连接,筛选不同课程但成绩相同的记录。
SELECT DISTINCT sc1.s_id, sc1.c_id, sc1.s_score
FROM score sc1
JOIN score sc2 ON sc1.s_score = sc2.s_score
AND sc1.c_id != sc2.c_id -- 不同课程
AND sc1.s_id = sc2.s_id; -- 同一学生
42. 查询每门课程成绩最好的前三名
思路:与第25题相同,用窗口函数取每门课程前3名。
SELECT c_id,s_id,s_score,排名
FROM (SELECT *,ROW_NUMBER() OVER (PARTITION BY c_id ORDER BY s_score DESC) AS 排名FROM score
) AS r
WHERE 排名 <= 3;
43. 统计每门课程的学生选修人数(超过5人的课程才统计)
思路:按课程分组统计人数,用HAVING
筛选人数>5的课程。
SELECT c_id, COUNT(DISTINCT s_id) AS 选修人数
FROM score
GROUP BY c_id
HAVING 选修人数 > 5;
44. 检索至少选修两门课程的学生学号
思路:按学生分组,统计选课数≥2的学生。
SELECT s_id
FROM score
GROUP BY s_id
HAVING COUNT(c_id) >= 2;
45. 查询选修了全部课程的学生信息
思路:筛选选课数等于总课程数的学生。
-- 总课程数
SET @total_course = (SELECT COUNT(*) FROM course);SELECT s.*
FROM student s
JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id, s.s_name
HAVING COUNT(DISTINCT sc.c_id) = @total_course;
46. 查询各学生的年龄(周岁)
思路:用TIMESTAMPDIFF
计算当前日期与出生日期的年份差(当前日期用CURDATE()
)。
SELECT s_id,s_name,TIMESTAMPDIFF(YEAR, s_birth, CURDATE()) AS 年龄
FROM student;
47. 查询本周过生日的学生
思路:用WEEKOFYEAR()
获取生日所在周,与当前周对比(注意:每年的周数可能跨年份,需统一按“今年的生日”计算)。
SELECT *
FROM student
WHERE WEEKOFYEAR(DATE_FORMAT(s_birth, CONCAT(YEAR(CURDATE()), '-%m-%d'))) = WEEKOFYEAR(CURDATE());
48. 查询下周过生日的学生
思路:与第47题类似,筛选生日所在周=当前周+1。
SELECT *
FROM student
WHERE WEEKOFYEAR(DATE_FORMAT(s_birth, CONCAT(YEAR(CURDATE()), '-%m-%d'))) = WEEKOFYEAR(CURDATE()) + 1;
49. 查询本月过生日的学生
思路:用MONTH()
提取生日月份,与当前月份对比。
SELECT *
FROM student
WHERE MONTH(s_birth) = MONTH(CURDATE());
50. 查询12月份过生日的学生
思路:筛选生日月份=12的学生。
SELECT *
FROM student
WHERE MONTH(s_birth) = 12;