面试被问过两次
假设有一个成绩表,其中有姓名、科目、成绩三个字段,如何查询出各科成绩的前三名
使用窗口函数的解决方案
SELECT
subject,
name,
score
FROM (
SELECT
subject,
name,
score,
DENSE_RANK() OVER (PARTITION BY subject ORDER BY score DESC) rk
FROM
test.subject_scores
) RankedScores
WHERE
rk <= 3
ORDER BY
subject,
score DESC;
实现思路
- 使用
DENSE_RANK()
窗口函数对每个科目的学生按照成绩降序排名。 - 在外部查询中选择排名在前三的学生。
- 最终的结果按科目升序和成绩降序排序。
优势
- 简洁性:窗口函数提供了更简洁的方式获取排名信息。
- 可读性:易读且直观,提高了查询的可读性。
使用子查询的解决方案
使用子查询涉及到两个独立的子查询,其中一个处理普通排名,另一个处理并列排名。
SELECT
subject,
name,
score
FROM test.subject_scores s1
WHERE (
SELECT COUNT(DISTINCT score)
FROM test.subject_scores s2
WHERE s2.subject = s1.subject AND s2.score > s1.score
) < 3 OR (
SELECT COUNT(DISTINCT score)
FROM test.subject_scores s3
WHERE s3.subject = s1.subject AND s3.score = s1.score
) >= 3
ORDER BY
subject,
score DESC;
实现思路
- 第一个子查询计算当前学生在当前科目的成绩高于的学生数量,用于普通排名。
- 第二个子查询计算与当前学生成绩相同的学生数量,用于处理并列排名。
- 使用 OR 连接两个条件,确保选择前三名学生或处理并列排名的情况。
缺点
- 逻辑复杂性:包含两个子查询,增加了查询的逻辑复杂性。
总结
版本支持情况下( MySQL>=8.0 ),优先选择窗口函数方案