一、知识点总结
把有用的知识写在前面,以方便自个儿复习观看😊
1)窗口函数:有三种排序方式
- rank() over() 1 2 2 4 4 6 (计数排名,跳过相同的几个,eg.没有3没有5)
- row_number() over() 1 2 3 4 5 6 (赋予唯一排名)
- dense_rank() over() 1 2 2 3 3 4 (不跳过排名,可以理解为对类别进行计数)
2)聚合函数:通常查找最大值最小值的时候,首先会想到使用聚合函数。
a.group by的常见搭配:常和以下聚合函数搭配
- avg()-- 求平均值
- count()-- 计数
- sum()-- 求和
- max() -- 最大值
- min()-- 最小值
b.group by 的进阶用法,和with rollup一起使用。
3)左右连接
左连接:表1 left join 表2 on 表1.字段=表2.字段 (以表1为准,表2进行匹配)
右连接:表1 right join 表2 on 表1.字段=表2.字段 (以表2为准,表1进行匹配)
全连接:表1 union all 表2 (表1 和表2的列数必须一样多,union 去除重复项,union all 不剔除重复项)
内连接:表1 inner join 表2(取表1和表2相交部分)
外连接:表1 full outer join 表2 (取表1和表2不相交的部分)
ps:MYSQL 不支持外连接,可以用左右连接后再全连接代替
二、题目解读与解题步骤拆解
1、题目解读
求:找到每类试卷得分的前3名,如果两人最大分数相同,选择最小分数大者,如果还相同,选择uid大者。
题目中隐藏的坑
题目中隐藏的坑
- 坑1:每类试卷得分的前3名,因此不包含一个用户独占一科前几名的情况,例如1003的SQL考试分别是89分和86分,只取分高的那条数据。本质就是对比某科目每个用户的最高分。
- 坑2:如果最高分一样,那就对比最低分:order by max(score) desc,min(score) desc,uid desc
2、解题步骤拆分
先处理表格找出每个科目各用户的最高分与最低分,进行排序,最后取前3。
排序常用row_number()匹配窗口函数。需求字段:tag,uid,ranking
三、步骤代码
1)tag取值
SELECT tag FROM examination_info
SELECT uid FROM exam_record
SELECT b.tag,a.uid,max(a.score),min(a.score) FROM exam_record a LEFT JOIN examination_info b ON a.exam_id=b.exam_id GROUP BY b.tag,a.uid;
处理后表格如下
ROW_NUMBER()OVER(PARTITION BY tag ORDER BY max(a.score)DESC,min(a.score)DESC,a.uid DESC) ranking
SELECT b.tag,a.uid,max(a.score),min(a.score),/*这里写max(a.score)和min(a.score)是为了帮助理解窗口函数里的ORDER BY 后面的内容*/ ROW_NUMBER()OVER(PARTITION BY tag ORDER BY max(a.score)DESC,min(a.score)DESC,a.uid DESC) ranking FROM exam_record a LEFT JOIN examination_info b ON a.exam_id=b.exam_id GROUP BY b.tag,a.uid;
四、完整代码组装
SELECT tag,uid,ranking FROM ( SELECT b.tag,a.uid, ROW_NUMBER()OVER(PARTITION BY tag ORDER BY max(a.score) DESC,min(a.score) DESC,a.uid DESC) ranking /*先按照最高分,再按照最低分排,最后按照uid排序 */ FROM exam_record a LEFT JOIN examination_info b ON a.exam_id=b.exam_id GROUP BY b.tag,a.uid)t1 WHERE ranking<=3最终结果