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

经典SQL查询问题的练习第二天

📝 第二天SQL打卡题目
表结构不变:  
- `student(studentId, studentName)`  
- `course(courseId, courseName, teacher)`  
- `score(score, studentId, courseId)`  

1. 查询未选修任何课程的学生姓名(考察:NOT EXISTS / LEFT JOIN + NULL) 
```sql
-- 方案1:NOT EXISTS
SELECT studentName 
FROM student s
WHERE NOT EXISTS (
    SELECT 1 FROM score sc WHERE sc.studentId = s.studentId
);

-- 方案2:LEFT JOIN + IS NULL
SELECT s.studentName
FROM student s
LEFT JOIN score sc ON s.studentId = sc.studentId
WHERE sc.courseId IS NULL;
```

2. 查询每门课程成绩最高的学生姓名及分数(考察:窗口函数 RANK() / 子查询) 
```sql
-- 窗口函数方案(推荐)
SELECT courseName, studentName, score
FROM (
    SELECT 
        c.courseName, 
        s.studentName, 
        sc.score,
        RANK() OVER (PARTITION BY sc.courseId ORDER BY sc.score DESC) AS rk
    FROM score sc
    JOIN student s ON sc.studentId = s.studentId
    JOIN course c ON sc.courseId = c.courseId
) t
WHERE t.rk = 1;
```

3. 查询所有课程平均分高于全体学生总平均分的课程名称(考察:聚合函数嵌套 + HAVING)
```sql
SELECT 
    c.courseName,
    AVG(sc.score) AS avg_score
FROM score sc
JOIN course c ON sc.courseId = c.courseId
GROUP BY c.courseId, c.courseName
HAVING AVG(sc.score) > (
    SELECT AVG(score) FROM score  -- 全体学生总平均分
);
```

4. 查询至少有一门课成绩超过90分的学生中,总成绩排名前5的学生(考察:子查询 + 复合条件排序)
```sql
SELECT 
    s.studentId,
    s.studentName,
    SUM(sc.score) AS total_score
FROM student s
JOIN score sc ON s.studentId = sc.studentId
WHERE s.studentId IN (
    SELECT DISTINCT studentId 
    FROM score 
    WHERE score > 90  -- 至少一门课>90分
)
GROUP BY s.studentId, s.studentName
ORDER BY total_score DESC
LIMIT 5;
```

5. 查询每个学生成绩最高的课程及对应教师(考察:关联子查询 + 多表JOIN)
```sql
SELECT 
    s.studentName,
    c.courseName,
    c.teacher,
    sc.score
FROM score sc
JOIN student s ON sc.studentId = s.studentId
JOIN course c ON sc.courseId = c.courseId
WHERE sc.score = (
    SELECT MAX(score) 
    FROM score 
    WHERE studentId = sc.studentId  -- 关联当前学生
);
```

6. 优化题:如何为`score`表设计索引以加速以下查询?(考察:索引设计原则)
```sql
-- 查询语句:
SELECT studentId, AVG(score) 
FROM score 
WHERE courseId = '0006'
GROUP BY studentId;
```
参考答案:  
```sql
CREATE INDEX idx_course_student ON score(courseId, studentId, score);
```
原理:  
- `WHERE courseId` 作为第一条件用等值查询  
- `GROUP BY studentId` 需有序访问,故作为第二列  
- 覆盖索引(包含`score`)避免回表查数据   

题目一解释:
找那些"啥课都没选"的学生。想象一个班级点名册(student表),我们要找出名字从来没出现在任何课程成绩单(score表)上的学生。

  • 方法1:用"不存在"(NOT EXISTS)逻辑,相当于问"这个学生在成绩单上完全不存在记录吗?"

  • 方法2:用"左连接+空值"(LEFT JOIN + IS NULL),相当于把点名册和成绩单并排摊开,看哪些学生右边成绩单位置是空的

题目二解释:
找出每门课的"状元"(最高分学生)。就像学校公布的光荣榜,每科都要展示第一名学生和分数。

  • 关键技巧:用"窗口函数"(RANK())给每门课的学生按分数排名(类似Excel的分组排序)

  • 最后只取每科排名第1的学生

题目三解释:
找出"学霸课程"——这些课的平均分比全校总平均分还高。就像比较每个班级平均分和年级平均分。

  • 先算全校总平均分(子查询)

  • 再算每门课平均分(GROUP BY课程)

  • 最后筛选出班级平均分 > 全校平均分的课程

题目四解释:
先找出"有单科90分以上"的学生,再在这些学霸中找"总分前5名"。

  • 第一步:用子查询筛出至少有一门90+的学生(成绩单里挑出90+的学号)

  • 第二步:计算这些学生的总分并排名

  • 第三步:取前5名(LIMIT 5)

题目五解释:
给每个学生找出"最拿手的科目"(最高分的课程)和任课老师。

  • 核心思路:对每个学生,找到他的最高分记录

  • 实现方式:关联子查询(WHERE sc.score = 该学生最高分)

  • 最后关联课程表获取老师信息

题目六解释:
给成绩单(score表)建"快速查询通道"(索引)。

  • 问题:要快速查某个课程(如0006)所有学生的平均分

  • 解决方案:建三层快速通道

    1. 第一层按课程ID分类(courseId)

    2. 第二层按学生ID排序(studentId)

    3. 第三层直接带分数值(score)避免翻原始成绩单

  • 效果:像图书馆先按楼层→区域→书架找书,比全馆瞎找快10倍

相关文章:

  • JNI开发流程
  • OS9.【Linux】基本权限(下)
  • Vue-收集表单信息
  • 动态IP与区块链:重构网络信任的底层革命
  • Maven高级篇
  • 迈迪工具集添加标准件
  • 【征求意见】四川省大数据发展研究会关于对《数据资源建设费用测算标准》团体标准征求意见的通知
  • ASR、TTS与语音克隆技术简介
  • LevelDB、BoltDB 和 RocksDB区块链应用比较
  • 一、虚拟货币概述
  • NewsNow:免费好用的实时新闻聚合平台,让信息获取更优雅(深度解析、部署攻略)
  • 【题解-洛谷】P4387 【深基15.习9】验证栈序列
  • 防爆连接器3芯4芯5芯 增安型航空插头
  • 【ROS2实体机械臂驱动】rokae xCoreSDK Python测试使用
  • 计算机模拟分子合成有哪些应用软件?
  • Java Math类API全解析
  • xQueueSendFromISR使用
  • Flink2.0及Flink-operater在K8S上部署
  • HTML 文件反编译指南:优化与学习网页代码
  • Jvm 元空间大小分配原则
  • 关于门户网站建设报告/seo搜索引擎官网
  • 建设网站需要的编程/竞价销售是什么意思
  • 企业管理软件销售/搜索引擎优化管理实验报告
  • 建筑单位资质/北京网站优化服务商
  • 网站登录按纽是灰色的/创意营销
  • .net做的大型网站吗/详情页页面页面