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

第三天 SQL 打卡题目

表结构不变

  • student(studentId, studentName)

  • course(courseId, courseName, teacher)

  • score(score, studentId, courseId)


1. 查询每个老师授课的学生人数(考察:多表连接 + 聚合函数)
SELECT 
    c.teacher,
    COUNT(DISTINCT sc.studentId) AS student_count
FROM course c
LEFT JOIN score sc ON c.courseId = sc.courseId
GROUP BY c.teacher;

通俗解释
统计每位老师教了多少学生。

  • 先通过课程表连接成绩表,找到每门课的学生

  • COUNT(DISTINCT)确保同一学生选多门课不重复计数


2. 查询课程平均分高于教师平均授课分的课程(考察:嵌套聚合 + 子查询)
SELECT 
    c.courseName,
    AVG(sc.score) AS course_avg
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
    JOIN course ON score.courseId = course.courseId
    WHERE course.teacher = c.teacher  -- 同教师课程
);

通俗解释
找出"教得比其他课好"的课程。

  • 先计算该教师所有课的平均分(子查询)

  • 再筛选单科平均分 > 教师平均分的课程


3. 查询所有学生按总成绩排名的百分比(考察:窗口函数 + 百分比计算)
SELECT
    studentId,
    studentName,
    total_score,
    ROUND(PERCENT_RANK() OVER (ORDER BY total_score) * 100, 2) AS percent_rank
FROM (
    SELECT 
        s.studentId,
        s.studentName,
        SUM(sc.score) AS total_score
    FROM student s
    JOIN score sc ON s.studentId = sc.studentId
    GROUP BY s.studentId, s.studentName
) t;

通俗解释
计算每个学生的总分在年级的百分比排名(如超过90%同学)。

  • 内层:计算每个学生总分

  • 外层:用PERCENT_RANK()计算百分比排名


4. 查询选课完全相同的两两学生组合(考察:自连接 + 集合匹配)
SELECT 
    a.studentId AS student1,
    b.studentId AS student2
FROM (
    SELECT studentId, GROUP_CONCAT(courseId ORDER BY courseId) AS courses 
    FROM score 
    GROUP BY studentId
) a
JOIN (
    SELECT studentId, GROUP_CONCAT(courseId ORDER BY courseId) AS courses 
    FROM score 
    GROUP BY studentId
) b ON a.courses = b.courses AND a.studentId < b.studentId;

通俗解释
找"课表双胞胎"(选课完全一样的学生对)。

  • GROUP_CONCAT把每个学生的选课拼接成字符串(如"0001,0002")

  • 通过字符串匹配找到选课完全相同的学生对


5. 查询成绩波动大于30%的学生课程记录(考察:窗口函数 + 波动计算)
SELECT 
    studentId,
    courseId,
    score,
    prev_score,
    ROUND(ABS(score - prev_score) / prev_score * 100, 2) AS change_percent
FROM (
    SELECT 
        *,
        LAG(score) OVER (PARTITION BY studentId ORDER BY courseId) AS prev_score
    FROM score
) t
WHERE prev_score IS NOT NULL 
  AND ABS(score - prev_score) / prev_score > 0.3;

通俗解释
找出"成绩坐过山车"的记录(比上次成绩波动超30%)。

  • LAG()获取同一学生前一门课成绩

  • 计算当前成绩相对前次的波动百分比


6. 优化题:如何优化多字段分组的大数据量查询?(考察:组合索引 + 最左前缀)
-- 原始查询:
SELECT teacher, courseId, AVG(score)
FROM course c
JOIN score s ON c.courseId = s.courseId
GROUP BY teacher, courseId;

参考答案

ALTER TABLE course ADD INDEX idx_teacher_course (teacher, courseId);
ALTER TABLE score ADD INDEX idx_course (courseId);

优化原理

  1. 课程表按(teacher, courseId)建索引:

    • 直接定位教师+课程分组

  2. 成绩表按courseId建索引:

    • 快速关联课程表获取教师信息

  3. 避免全表扫描,分组速度提升10倍


每日考点总结

题号 核心考点 实际应用场景
1 多表连接 + 去重计数 教师工作量统计
2 嵌套聚合比较 教学质量评估
3 百分比排名 学生成绩分布分析
4 集合匹配 + 自连接 学习兴趣群体发现
5 窗口函数 + 波动计算 成绩稳定性预警
6 复合索引设计 大数据量报表性能优化

你可能感兴趣的:(sql,测开,数据库,sql,mysql)