当前位置: 首页 > backend >正文

MySQL 基础练习(50 题完整解析)


MySQL 基础练习(50 题完整解析)

1. 数据准备

建表

CREATE TABLE Student(SId VARCHAR(10),Sname VARCHAR(10),Sage DATETIME,Ssex VARCHAR(10)
);CREATE TABLE Course(CId VARCHAR(10),Cname NVARCHAR(10),TId VARCHAR(10)
);CREATE TABLE Teacher(TId VARCHAR(10),Tname VARCHAR(10)
);CREATE TABLE SC(SId VARCHAR(10),CId VARCHAR(10),score DECIMAL(18,1)
);

插入数据

-- 学生表
INSERT INTO Student VALUES('01','赵雷','1990-01-01','男');
INSERT INTO Student VALUES('02','钱电','1990-12-21','男');
INSERT INTO Student VALUES('03','孙风','1990-12-20','男');
INSERT INTO Student VALUES('04','李云','1990-12-06','男');
INSERT INTO Student VALUES('05','周梅','1991-12-01','女');
INSERT INTO Student VALUES('06','吴兰','1992-01-01','女');
INSERT INTO Student VALUES('07','郑竹','1989-01-01','女');
INSERT INTO Student VALUES('09','张三','2017-12-20','女');
INSERT INTO Student VALUES('10','李四','2017-12-25','女');
INSERT INTO Student VALUES('11','李四','2012-06-06','女');
INSERT INTO Student VALUES('12','赵六','2013-06-13','女');
INSERT INTO Student VALUES('13','孙七','2014-06-01','女');-- 课程表
INSERT INTO Course VALUES('01','语文','02');
INSERT INTO Course VALUES('02','数学','01');
INSERT INTO Course VALUES('03','英语','03');-- 教师表
INSERT INTO Teacher VALUES('01','张三');
INSERT INTO Teacher VALUES('02','李四');
INSERT INTO Teacher VALUES('03','王五');-- 成绩表
INSERT INTO SC VALUES('01','01',80);
INSERT INTO SC VALUES('01','02',90);
INSERT INTO SC VALUES('01','03',99);
INSERT INTO SC VALUES('02','01',70);
INSERT INTO SC VALUES('02','02',60);
INSERT INTO SC VALUES('02','03',80);
INSERT INTO SC VALUES('03','01',80);
INSERT INTO SC VALUES('03','02',80);
INSERT INTO SC VALUES('03','03',80);
INSERT INTO SC VALUES('04','01',50);
INSERT INTO SC VALUES('04','02',30);
INSERT INTO SC VALUES('04','03',20);
INSERT INTO SC VALUES('05','01',76);
INSERT INTO SC VALUES('05','02',87);
INSERT INTO SC VALUES('06','01',31);
INSERT INTO SC VALUES('06','03',34);
INSERT INTO SC VALUES('07','02',89);
INSERT INTO SC VALUES('07','03',98);

2. 练习题与答案

1. 查询"01"课程比"02"课程成绩高的学生的信息及课程分数

SELECT s.*, sc1.score AS score01, sc2.score AS score02
FROM Student s
JOIN SC sc1 ON s.SId = sc1.SId AND sc1.CId = '01'
JOIN SC sc2 ON s.SId = sc2.SId AND sc2.CId = '02'
WHERE sc1.score > sc2.score;

解析:用同一张 SC 表做两次连接,比较两个课程成绩。

语义逐行拆解

  1. SELECT s.*, sc1.score AS score01, sc2.score AS score02

    • 返回 Student 表中该行的所有列(设置别名 s 表示),并额外返回两列 score01(学号对应的 01 课程分数)和 score02(对应的 02 课程分数)。

  2. FROM Student s

    • Student 表为基础表(别名 s)。

  3. JOIN SC sc1 ON s.SId = sc1.SId AND sc1.CId = '01'

    • SC 表做一次 内连接(INNER JOIN),设置别名为 sc1,并且在 ON 中同时指定了连接条件 s.SId = sc1.SIdsc1.CId = '01'

    • 也就是说 sc1 只包含课程为 01 的成绩记录,且只连接那些 Student01 课程成绩的行。

  4. JOIN SC sc2 ON s.SId = sc2.SId AND sc2.CId = '02'

    • 再对 SC 表做一次内连接(设置别名 sc2),sc2 只包含课程为 02 的成绩记录;因此只有同时有 0102 两条成绩记录的学生才会出现在中间结果中。

  5. WHERE sc1.score > sc2.score

    • 过滤条件:01 课程的分数必须严格大于 02 课程的分数。只有满足该条件的行才返回。

2. 查询同时存在 "01" 课程和 "02" 课程的情况

SELECT sc1.SId
FROM SC sc1
JOIN SC sc2 ON sc1.SId = sc2.SId
WHERE sc1.CId = '01' AND sc2.CId = '02';

解析

  • 核心逻辑:通过自连接(SC 表自己关联自己),将同一学生(sc1.SId = sc2.SId)的两条选课记录关联起来。
  • 条件筛选:sc1.CId = '01' 确保第一条记录是 “01” 课程,sc2.CId = '02' 确保第二条记录是 “02” 课程,两者结合即找到同时选了两门课的学生 ID。
  • 应用场景:适用于需要验证 “用户同时满足两个条件” 的场景(如同时购买 A 和 B 商品的用户)。

3. 查询存在 "01" 课程但可能不存在 "02" 课程的情况

SELECT sc1.SId, sc1.score AS score01, sc2.score AS score02
FROM SC sc1
LEFT JOIN SC sc2 ON sc1.SId = sc2.SId AND sc2.CId = '02'
WHERE sc1.CId = '01';

解析

  • 连接逻辑:LEFT JOIN 保证 “01” 课程的学生记录(sc1)全部保留,即使该学生没选 “02” 课程,sc2 的字段(如score02)会显示为NULL
  • 条件设计:ON 子句中sc2.CId = '02' 限定关联的是 “02” 课程记录,而非WHERE子句(若放WHERE会过滤掉sc2NULL的记录,失去 LEFT JOIN 的意义)。
  • 结果意义:返回所有选了 “01” 课程的学生,同时显示他们 “02” 课程的成绩(若有),方便对比同一学生两门课的表现。

4. 查询不存在 "01" 课程但存在 "02" 课程的情况

SELECT sc2.SId, sc2.score AS score02
FROM SC sc2
LEFT JOIN SC sc1 ON sc2.SId = sc1.SId AND sc1.CId = '01'
WHERE sc2.CId = '02' AND sc1.SId IS NULL;

解析

  • 核心思路:先通过LEFT JOIN尝试将 “02” 课程的学生(sc2)与 “01” 课程记录(sc1)关联,若关联失败(sc1.SId IS NULL),说明该学生没有 “01” 课程记录。
  • 条件验证:sc2.CId = '02' 确保基础是 “02” 课程的学生,sc1.SId IS NULL 排除有 “01” 课程的学生,最终得到 “只选了 02 但没选 01” 的学生。

5. 查询平均成绩 ≥ 60 的学生学号、姓名、平均成绩

SELECT s.SId, s.Sname, AVG(sc.score) AS avg_score
FROM Student s
JOIN SC sc ON s.SId = sc.SId
GROUP BY s.SId, s.Sname
HAVING AVG(sc.score) >= 60;

解析

  • 分组与聚合:GROUP BY s.SId, s.Sname 按学生分组(SId唯一标识学生,Sname随分组保留),AVG(sc.score) 计算每组(学生)的平均成绩。
  • HAVING 作用:用于分组后筛选(与WHERE的区别:WHERE在分组前过滤行,HAVING在分组后过滤组)。此处需先计算平均分再筛选达标的学生。
  • 标准 SQL 要求:SELECT中非聚合字段(如s.SIds.Sname)必须出现在GROUP BY中,否则结果无意义。

6. 查询在 SC 表存在成绩的学生信息

SELECT DISTINCT s.*
FROM Student s
JOIN SC sc ON s.SId = sc.SId;

解析

  • 连接目的:JOIN SC 确保只保留有选课记录(即有成绩)的学生。
  • DISTINCT 必要性:一个学生可能选多门课(SC 表有多条记录),JOIN后会生成重复的学生信息,DISTINCT 去重确保每个学生只显示一次。

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

SELECT s.SId, s.Sname, COUNT(sc.CId) AS course_count, SUM(sc.score) AS total_score
FROM Student s
LEFT JOIN SC sc ON s.SId = sc.SId
GROUP BY s.SId, s.Sname;

解析

  • LEFT JOIN 关键作用:保留所有学生(包括未选课的学生),未选课的学生因sc.CIdNULLCOUNT(sc.CId) 会统计为 0,SUM(sc.score) 会统计为NULL(可通过IFNULL转为 0)。
  • 聚合逻辑:COUNT(sc.CId) 统计选课数量(COUNT(*)会包含NULL,此处需排除),SUM(sc.score) 累加所有课程成绩。

8. 查询姓「李」的老师数量

SELECT COUNT(*) AS teacher_count
FROM Teacher
WHERE Tname LIKE '李%';

解析

  • 通配符LIKE'李%' 中%匹配任意长度的字符(包括 0 个),表示 “以‘李’开头的姓名”,精准筛选所有姓李的老师。
  • COUNT(*):统计符合条件的记录总数,即姓李的老师人数。

9. 查询学过「张三」老师授课的学生信息

SELECT DISTINCT s.*
FROM Student s
JOIN SC sc ON s.SId = sc.SId
JOIN Course c ON sc.CId = c.CId
JOIN Teacher t ON c.TId = t.TId
WHERE t.Tname = '张三';

解析

  • 多表连接链:Student → SC → Course → Teacher,通过关联找到 “学生→选课→课程→授课老师” 的关系,最终定位到张三老师的课程。
  • DISTINCT 去重:一个学生可能选多门张三老师的课,JOIN后会生成多条重复的学生记录,需去重。

10. 查询没有学全所有课程的学生信息

SELECT *
FROM Student
WHERE SId NOT IN (SELECT SIdFROM SCGROUP BY SIdHAVING COUNT(DISTINCT CId) = (SELECT COUNT(*) FROM Course)
);

解析

  • 子查询逻辑:内层子查询先找出 “学全所有课程” 的学生 —— 按学生分组后,若其选修的不同课程数(COUNT(DISTINCT CId))等于总课程数(SELECT COUNT(*) FROM Course),则为 “学全”。
  • 外层取反:NOT IN 排除 “学全” 的学生,得到 “未学全” 的学生信息。

11. 查询至少有一门课与学号为 "01" 的同学所学相同的同学信息

SELECT DISTINCT s.*
FROM Student s
JOIN SC sc ON s.SId = sc.SId
WHERE sc.CId IN (SELECT CId FROM SC WHERE SId = '01'
) AND s.SId <> '01';

解析

  • 子查询定位:SELECT CId FROM SC WHERE SId = '01' 先找出 01 同学学过的所有课程 ID。
  • 外层匹配:sc.CId IN (...) 筛选出选了这些课程的学生,s.SId <> '01' 排除 01 同学本人,DISTINCT 去重(同一学生可能选多门重合课程)。

12. 查询和 "01" 号同学学习的课程完全相同的其他同学信息

SELECT s.*
FROM Student s
WHERE s.SId <> '01'
AND NOT EXISTS (SELECT CId FROM SC WHERE SId = '01'EXCEPTSELECT CId FROM SC WHERE SId = s.SId
)
AND NOT EXISTS (SELECT CId FROM SC WHERE SId = s.SIdEXCEPTSELECT CId FROM SC WHERE SId = '01'
);

解析

  • 集合差集EXCEPT:返回第一个集合中有但第二个集合中没有的记录(如 A 课程集EXCEPTB 课程集,得到 A 有而 B 没有的课程)。
  • 双重NOT EXISTS
    • 第一个NOT EXISTS:01 的课程 减去 该学生的课程 结果为空(即该学生包含 01 的所有课程)。
    • 第二个NOT EXISTS:该学生的课程 减去 01 的课程 结果为空(即该学生没有 01 以外的课程)。
    • 两者结合:该学生与 01 的课程完全一致(集合相等)。

13. 查询没学过 "张三" 老师任一课程的学生姓名

SELECT s.Sname
FROM Student s
WHERE s.SId NOT IN (SELECT sc.SIdFROM SC scJOIN Course c ON sc.CId = c.CIdJOIN Teacher t ON c.TId = t.TIdWHERE t.Tname = '张三'
);

解析

  • 子查询逻辑:通过SC → Course → Teacher关联,找出所有选过张三老师课程的学生 ID。
  • 外层排除:NOT IN 筛选出不在子查询结果中的学生,即 “没学过张三任何课程” 的学生姓名。

14. 查询两门及以上不及格课程的学生学号、姓名及平均成绩

SELECT s.SId, s.Sname, AVG(sc.score) AS avg_score
FROM Student s
JOIN SC sc ON s.SId = sc.SId
WHERE sc.score < 60
GROUP BY s.SId, s.Sname
HAVING COUNT(*) >= 2;

解析

  • 分步筛选:
    1. WHERE sc.score < 60 先过滤出所有不及格的成绩记录。
    2. 按学生分组后,COUNT(*) 统计每个学生的不及格课程数。
    3. HAVING COUNT(*) >= 2 筛选出至少两门不及格的学生,并计算他们的平均成绩(含及格和不及格课程)。

15. 检索 "01" 课程分数 < 60,按分数降序排列的学生信息

SELECT s.*, sc.score
FROM Student s
JOIN SC sc ON s.SId = sc.SId
WHERE sc.CId = '01' AND sc.score < 60
ORDER BY sc.score DESC;

解析

  • 条件定位:sc.CId = '01' AND sc.score < 60 精准找到 01 课程不及格的学生。
  • 排序目的:ORDER BY sc.score DESC 按分数从高到低排列,方便快速查看不及格学生中分数较高(接近及格)的群体。

16. 按平均成绩从高到低显示所有学生的课程成绩及平均成绩

SELECT s.SId, s.Sname, c.Cname, sc.score, t.avg_score
FROM SC sc
JOIN Student s ON sc.SId = s.SId
JOIN Course c ON sc.CId = c.CId
JOIN (SELECT SId, AVG(score) AS avg_scoreFROM SC GROUP BY SId
) t ON s.SId = t.SId
ORDER BY t.avg_score DESC;

解析

  • 子查询作用:提前计算每个学生的平均成绩(t.avg_score),避免重复计算,提升效率。
  • 关联逻辑:将学生的单科成绩(sc.score)与平均成绩(t.avg_score)关联,方便同时查看 “单科表现” 和 “整体水平”,并按平均分排序。

17. 查询各科成绩最高分、最低分、平均分、及格率等

SELECT c.CId, c.Cname,MAX(sc.score) AS max_score,MIN(sc.score) AS min_score,AVG(sc.score) AS avg_score,SUM(sc.score >= 60)/COUNT(*) AS pass_rate,SUM(sc.score BETWEEN 70 AND 79)/COUNT(*) AS mid_rate,SUM(sc.score BETWEEN 80 AND 89)/COUNT(*) AS good_rate,SUM(sc.score >= 90)/COUNT(*) AS excellent_rate,COUNT(*) AS stu_count
FROM SC sc
JOIN Course c ON sc.CId = c.CId
GROUP BY c.CId, c.Cname
ORDER BY stu_count DESC, c.CId ASC;

解析

  • 聚合函数组合:MAX/MIN/AVG 分别计算最高分、最低分、平均分;
  • 条件计数技巧:SUM(条件) 中,条件为TRUE时返回 1,FALSE时返回 0,因此SUM(sc.score >= 60) 即 “及格人数”,除以总人数(COUNT(*))得到及格率。
  • 排序逻辑:先按选课人数(stu_count)降序(关注热门课程),人数相同则按课程 ID 升序(保证稳定排序)。

18. 按各科平均成绩排序(保留名次空缺)

SELECT c.CId, c.Cname, t.avg_score,RANK() OVER (ORDER BY t.avg_score DESC) AS rank_num
FROM (SELECT CId, AVG(score) AS avg_scoreFROM SC GROUP BY CId
) t
JOIN Course c ON t.CId = c.CId;

解析

  • 窗口函数RANK():用于排名,特点是 “保留名次空缺”—— 若有 n 个并列第 k 名,则下一名为 k+n(如两个第 1 名,下一名为第 3)。
  • 排序依据:ORDER BY t.avg_score DESC 按平均成绩从高到低排名,反映各科整体难度或学生掌握程度。

19. 按各科平均成绩排序(不保留名次空缺)

SELECT c.CId, c.Cname, t.avg_score,DENSE_RANK() OVER (ORDER BY t.avg_score DESC) AS rank_num
FROM (SELECT CId, AVG(score) AS avg_scoreFROM SC GROUP BY CId
) t
JOIN Course c ON t.CId = c.CId;

解析

  • 窗口函数DENSE_RANK():与RANK()的区别是 “不保留名次空缺”—— 若有并列第 k 名,下一名仍为 k+1(如两个第 1 名,下一名为第 2),适合需要连续名次的场景(如评选等级)。

20. 学生总成绩排名(保留名次空缺)

SELECT s.SId, s.Sname, t.total_score,RANK() OVER (ORDER BY t.total_score DESC) AS rank_num
FROM (SELECT SId, SUM(score) AS total_scoreFROM SC GROUP BY SId
) t
JOIN Student s ON s.SId = t.SId;

解析

  • 总成绩计算:SUM(score) 累加学生所有课程成绩得到总分(total_score)。
  • 排名逻辑:RANK() 按总分降序排名,保留空缺(如两个满分学生并列第 1,下一名为第 3),适合需要严格区分名次的场景(如奖学金评定)。

21. 学生总成绩排名(不保留名次空缺)

SELECT s.SId, s.Sname, t.total_score,DENSE_RANK() OVER (ORDER BY t.total_score DESC) AS rank_num
FROM (SELECT SId, SUM(score) AS total_scoreFROM SC GROUP BY SId
) t
JOIN Student s ON s.SId = t.SId;

解析

  • 核心差异:使用DENSE_RANK() 确保名次连续,即使有并列分数,也不会跳过名次(如两个满分学生并列第 1,下一名为第 2),适合需要分组统计(如 “前 10%”“前 20%”)的场景。

22. 各科成绩各分数段人数

SELECT c.CId, c.Cname,SUM(score BETWEEN 85 AND 100) AS '[100-85]',SUM(score BETWEEN 70 AND 84) AS '[85-70]',SUM(score BETWEEN 60 AND 69) AS '[70-60]',SUM(score < 60) AS '[60-0]',ROUND(SUM(score >= 85)/COUNT(*)*100,2) AS pct_85_100
FROM SC
JOIN Course c ON SC.CId = c.CId
GROUP BY c.CId, c.Cname;

解析

  • 分数段划分:BETWEEN a AND b 包含 a 和 b,精准划分区间(如85-100含 85 和 100);score < 60 直接筛选不及格。
  • 百分比计算:ROUND(...,2) 保留两位小数,SUM(score >=85)/COUNT(*)*100 计算高分段人数占比,反映课程难度(如高分段占比低可能课程较难)。

23. 各科成绩前三名

SELECT *
FROM (SELECT sc.*, RANK() OVER (PARTITION BY CId ORDER BY score DESC) AS rFROM SC sc
) t
WHERE r <= 3;

解析

  • 窗口函数分区:PARTITION BY CId 按课程分组,确保每个课程单独排名(而非所有课程混合排名)。
  • 排名筛选:RANK() OVER (...) AS r 按分数降序为每个课程的成绩排名,外层WHERE r <=3 取前三名(含并列,如某课程有 4 个并列第 3,则均会被选中)。

24. 每门课程选修人数

SELECT CId, COUNT(*) AS stu_count
FROM SC GROUP BY CId;

解析

  • 简单分组统计:按课程 ID(CId)分组,COUNT(*) 统计每个组的记录数(即选修该课程的学生数),直接反映课程的热门程度。

25. 只选修两门课程的学生

SELECT s.SId, s.Sname
FROM Student s
JOIN SC sc ON s.SId = sc.SId
GROUP BY s.SId, s.Sname
HAVING COUNT(DISTINCT CId) = 2;

解析

  • 去重计数:COUNT(DISTINCT CId) 统计学生选修的不同课程数量(排除重复选同一门课的情况),HAVING 筛选出数量等于 2 的学生,即 “只选修两门课”。

26. 男生、女生人数

SELECT Ssex, COUNT(*) AS cnt
FROM Student GROUP BY Ssex;

解析

  • 按性别分组:GROUP BY Ssex 将学生分为 “男”“女” 两组(假设Ssex只有这两个值),COUNT(*) 分别统计每组人数,用于性别比例分析。

27. 名字中含有「风」的学生信息

SELECT * FROM Student WHERE Sname LIKE '%风%';

解析

  • 通配符灵活匹配:%风% 中% 匹配任意字符(包括 0 个),表示 “姓名中任意位置包含‘风’字”(如 “林风”“风子”“李风明” 均会被匹配)。

28. 同名同性学生名单及人数

SELECT Sname, Ssex, COUNT(*) AS cnt
FROM Student
GROUP BY Sname, Ssex
HAVING COUNT(*) > 1;

解析

  • 联合分组:GROUP BY Sname, Ssex 确保 “同名且同性” 才会被分为一组(避免 “同名不同性” 被误判)。
  • 筛选重复:HAVING COUNT(*) > 1 只保留出现两次及以上的同名同性组合,方便排查重复信息或统计常见姓名。

29. 1990 年出生的学生

SELECT * FROM Student
WHERE YEAR(Sage) = 1990;

解析

  • 日期函数YEAR():从生日字段(Sage,假设为日期类型)中提取年份,与 1990 对比,精准筛选 1990 年出生的学生。

30. 每门课程平均成绩降序,平均相同按课程号升序

SELECT CId, AVG(score) AS avg_score
FROM SC
GROUP BY CId
ORDER BY avg_score DESC, CId ASC;

解析

  • 排序优先级:ORDER BY 先按avg_score DESC(平均成绩从高到低),若平均分相同,再按CId ASC(课程号从小到大),确保排序结果唯一、可预期。

31. 平均成绩 ≥ 85 的学生

SELECT s.SId, s.Sname, AVG(score) AS avg_score
FROM Student s
JOIN SC sc ON s.SId = sc.SId
GROUP BY s.SId, s.Sname
HAVING AVG(score) >= 85;

解析

  • 高分学生筛选:按学生分组计算平均分,HAVING 筛选出平均分≥85 的学生,用于识别优等生或推荐奖学金候选人。

32. 数学分数 < 60 的学生姓名和分数

SELECT s.Sname, sc.score
FROM SC sc
JOIN Student s ON sc.SId = s.SId
JOIN Course c ON sc.CId = c.CId
WHERE c.Cname = '数学' AND sc.score < 60;

解析

  • 多表关联定位:通过SC → Course 关联找到 “数学” 课程(c.Cname = '数学'),再筛选分数 < 60 的记录,最终关联学生表得到姓名,针对性查看数学不及格的学生。

33. 所有学生的课程及分数(含没选课的)

SELECT s.SId, s.Sname, c.Cname, sc.score
FROM Student s
CROSS JOIN Course c
LEFT JOIN SC sc ON s.SId = sc.SId AND c.CId = sc.CId;

解析

  • 笛卡尔积与左连接:CROSS JOIN Course 生成 “所有学生 × 所有课程” 的组合(即每个学生与每门课程都匹配一次),再通过LEFT JOIN SC 关联实际选课记录,未选课的组合中scoreNULL,确保结果包含所有学生的所有课程(无论是否选课)。

34. 任何一门课 ≥ 70 的学生姓名、课程名、分数

SELECT s.Sname, c.Cname, sc.score
FROM SC sc
JOIN Student s ON sc.SId = s.SId
JOIN Course c ON sc.CId = c.CId
WHERE sc.score >= 70;

解析

  • 简单条件筛选:sc.score >=70 直接筛选出所有及格及以上的成绩记录,关联学生和课程表后,展示 “学生 - 课程 - 分数” 对应关系,用于分析及格情况。

35. 不及格课程

SELECT DISTINCT CId FROM SC WHERE score < 60;

解析

  • 去重筛选:score <60 找出不及格记录,DISTINCT CId 确保每个有不及格记录的课程只显示一次,快速定位存在不及格情况的课程。

36. 01 课程成绩 ≥ 80 的学生

SELECT s.SId, s.Sname
FROM SC sc
JOIN Student s ON sc.SId = s.SId
WHERE sc.CId = '01' AND sc.score >= 80;

解析

  • 精准筛选:sc.CId = '01' 定位 01 课程,sc.score >=80 筛选高分学生,关联学生表得到 ID 和姓名,用于识别该课程的优秀学生。

37. 每门课程的学生人数

SELECT CId, COUNT(*) AS stu_count
FROM SC GROUP BY CId;

解析

  • 与第 24 题完全一致,按课程分组统计选课人数,基础且常用的课程热度分析。

38. 张三老师所授课程成绩最高的学生(成绩唯一)

SELECT s.*, sc.score
FROM SC sc
JOIN Course c ON sc.CId = c.CId
JOIN Teacher t ON c.TId = t.TId
JOIN Student s ON sc.SId = s.SId
WHERE t.Tname = '张三'
ORDER BY sc.score DESC LIMIT 1;

解析

  • 排序取顶:通过关联找到张三老师的课程,按分数降序排序后,LIMIT 1 取第一条记录(即最高分),适合成绩唯一的场景(若有并列最高分,仅取其中一条)。

39. 张三老师所授课程成绩最高的学生(成绩可能并列)

SELECT s.*, sc.score
FROM SC sc
JOIN Course c ON sc.CId = c.CId
JOIN Teacher t ON c.TId = t.TId
JOIN Student s ON sc.SId = s.SId
WHERE t.Tname = '张三'
AND sc.score = (SELECT MAX(sc2.score)FROM SC sc2JOIN Course c2 ON sc2.CId = c2.CIdJOIN Teacher t2 ON c2.TId = t2.TIdWHERE t2.Tname = '张三'
);

解析

  • 子查询取最高分:内层子查询先找出张三老师课程的最高分数(MAX(sc2.score)),外层筛选分数等于该最高分的学生,确保所有并列最高分的学生都被选中(解决第 38 题的并列问题)。

40. 不同课程成绩相同的学生

SELECT a.SId, a.CId, a.score
FROM SC a
JOIN SC b ON a.SId = b.SId AND a.CId <> b.CId AND a.score = b.score;

解析

  • 自连接条件:a.SId = b.SId 确保同一学生,a.CId <> b.CId 确保不同课程,a.score = b.score 确保分数相同,三者结合找出 “同一学生在不同课程中成绩相同” 的记录。

41. 每门课程成绩最好的前两名

SELECT *
FROM (SELECT sc.*, RANK() OVER (PARTITION BY CId ORDER BY score DESC) AS rFROM SC sc
) t
WHERE r <= 2;

解析

  • 与第 23 题逻辑一致,按课程分区排名后取前两名,含并列情况(如某课程有 3 个并列第 2,则均会被选中)。

42. 学生数超过 5 的课程

SELECT CId, COUNT(*) AS stu_count
FROM SC
GROUP BY CId
HAVING COUNT(*) > 5;

解析

  • 分组筛选:按课程分组后,HAVING COUNT(*) >5 筛选出选课人数超过 5 的课程,用于识别热门课程(需重点投入资源)。

43. 至少选修两门课程的学生

SELECT SId
FROM SC
GROUP BY SId
HAVING COUNT(DISTINCT CId) >= 2;

解析

  • 去重计数筛选:COUNT(DISTINCT CId) 统计学生选修的不同课程数,HAVING >=2 找出至少选两门课的学生 ID,用于分析学生的选课活跃度。

44. 选修了全部课程的学生

SELECT SId
FROM SC
GROUP BY SId
HAVING COUNT(DISTINCT CId) = (SELECT COUNT(*) FROM Course);

解析

  • 全量匹配:子查询SELECT COUNT(*) FROM Course 得到总课程数,若学生选修的不同课程数等于总课程数,则说明该学生选修了所有课程,用于识别 “全选课” 的学生。

45. 各学生年龄(按年份算)

SELECT SId, Sname, YEAR(CURDATE()) - YEAR(Sage) AS age
FROM Student;

解析

  • 简易年龄计算:YEAR(CURDATE()) 取当前年份,减去生日年份(YEAR(Sage))得到年龄,不考虑月份(如 1990 年 12 月和 1990 年 1 月出生的人会被算为同一年龄)。

46. 按生日精确计算年龄

SELECT SId, Sname,YEAR(CURDATE()) - YEAR(Sage) -(DATE_FORMAT(CURDATE(),'%m%d') < DATE_FORMAT(Sage,'%m%d')) AS age
FROM Student;

解析

  • 精确年龄逻辑:
    1. 基础年龄:当前年份 - 出生年份。
    2. 修正项:DATE_FORMAT(..., '%m%d') 提取月日,若当前月日 < 出生月日(即生日尚未过),则年龄减 1((条件) 为TRUE时返回 1,FALSE返回 0)。
  • 结果:精准计算年龄(如 2000 年 2 月 29 日出生,2023 年 3 月 1 日计算为 23 岁,2023 年 2 月 28 日计算为 22 岁)。

47. 本周过生日的学生

SELECT *
FROM Student
WHERE WEEK(Sage) = WEEK(CURDATE());

解析

  • 周数匹配:WEEK(Sage) 取生日所在的周数,WEEK(CURDATE()) 取当前周数,相等则为 “本周过生日”,注意:WEEK() 可能因数据库设置(如周一为周首还是周日)略有差异。

48. 下周过生日的学生

SELECT *
FROM Student
WHERE WEEK(Sage) = WEEK(CURDATE()) + 1;

解析

  • 周数加 1:当前周数加 1 即为下周,通过WEEK(Sage) 匹配,筛选出下周过生日的学生,方便提前准备祝福。

49. 本月过生日的学生

SELECT *
FROM Student
WHERE MONTH(Sage) = MONTH(CURDATE());

解析

  • 月份匹配:MONTH(Sage) 取生日月份,MONTH(CURDATE()) 取当前月份,相等则为 “本月过生日”,简单直接的月度生日筛选。

50. 下月过生日的学生

SELECT *
FROM Student
WHERE MONTH(Sage) = MONTH(CURDATE() + INTERVAL 1 MONTH);

解析

  • 月份偏移:CURDATE() + INTERVAL 1 MONTH 取 “当前日期加 1 个月”,MONTH() 提取其月份,与生日月份匹配,得到下月过生日的学生(自动处理 12 月加 1 月为次年 1 月的情况)。

http://www.xdnf.cn/news/17553.html

相关文章:

  • 【CV 目标检测】①——目标检测概述
  • VSCode编辑器常用24款基础插件
  • STM32 HAL库 HAL_TIM_OC_Start函数解读
  • 梯度裁剪总结
  • MCU的设计原理
  • AcWing 6479. 点格棋
  • MySQL 基础操作教程
  • PyTorch基础(使用Numpy实现机器学习)
  • 2025-8-11-C++ 学习 暴力枚举(2)
  • 面试题-----微服务业务
  • wed前端第三次作业
  • 本地文件夹与 GitHub 远程仓库绑定并进行日常操作的完整命令流程
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的多目标跟踪与行为分析优化(393)
  • Windows Server 2022域控制器部署与DNS集成方案
  • 机器学习中数据集的划分难点及实现
  • LangGraph 历史追溯 人机协同(Human-in-the-loop,HITL)
  • 通用 maven 私服 settings.xml 多源配置文件(多个仓库优先级配置)
  • OpenCV计算机视觉实战(19)——特征描述符详解
  • Python自动化测试实战:reCAPTCHA V3绕过技术深度解析
  • 关于JavaScript 性能优化的实战指南
  • 4-下一代防火墙组网方案
  • 需求列表如何做层级结构
  • Redis类型之Hash
  • vscode的wsl环境,怎么打开linux盘的工程?
  • 【Oracle】如何使用DBCA工具删除数据库?
  • 九,算法-递归
  • ​电风扇离线语音芯片方案设计与应用场景:基于 8 脚 MCU 与 WTK6900P 的创新融合
  • Spark 优化全攻略:从 “卡成 PPT“ 到 “飞一般体验“
  • Empire--安装、使用
  • 布控球:临时布防场景的高清回传利器-伟博