一、知识点总结与拓展

 本题所涉及到的知识点不多,困难点在于题目读起来比较拗口,以及一些关键信息藏在“解释”里。牛客的题,好多线索都喜欢放在“解释”里。
主要考察聚类窗口函数,和聚类窗口函数的用法和GROUP BY 函数类似。
  • MIN()OVER() :不改变表结构的前提下,计算出最小值
  • MAX()OVER():不改变表结构的前提下,计算出最大值
  • COUNT()OVER():不改变表结构的前提下,计数
  • SUM()OVER():不改变表结构的前提下,求和
  • AVG()OVER():不改变表结构的前提下,求平均值
在我的理解窗口函数的关键词是“不改变表格结构”,查出的数据,单独放一列

二、题目解读与解题步骤拆分

1、题目解读

题目:请你将用户作答高难度试卷的得分在每份试卷作答记录内执行min-max归一化后缩放到[0,100]区间,并输出用户ID、试卷ID、归一化后分数平均值;最后按照试卷ID升序、归一化分数降序输出。(注:得分区间默认为[0,100],如果某个试卷作答记录中只有一个得分,那么无需使用公式,归一化并缩放后分数仍为原分数)。

题目中隐藏的坑

坑1:某个试卷作答记录中只有一个得分,那么无需使用公式
坑2:归一化后分数平均值取整数(取自解释中的这句话“后两个得分都是用户1001作答的,因此用户1001对试卷9001的新得分为(95+100)/2≈98(只保留整数部分)”),因而,需要对同一个用户的归一化分数取平均值。
所以,做题一定要看“解释”的内容

需求字段

  • uid
  • exam_id
  • avg_new_score 最终归一结果

 

2、步骤拆分

1)用户作答高难度试卷的得分

  • 关联两张表,取difficulty='hard' 的数据

2)在每份试卷作答记录内执行min-max归一化

  • 归一化公示:min(score),max(score)
  • (score-min(score))/(max(score)-min(score))

3)如果某个试卷作答记录中只有一个得分,那么无需使用公式

  • 当min(score)=max(score)那就说明只有一个得分

4)归一化后缩放到[0,100]区间

  • 归一化结果*100

5)归一化后分数平均值取整数

6)按照试卷ID升序、归一化分数降序输出。

三、步骤代码

1)关联两张表,取difficulty='hard' 的数据,找出每类试卷的最小值和最大值

SELECT uid,a.exam_id,score,
    MIN(score) OVER(PARTITION BY exam_id) min_x, #求每类试卷的得分最小值
    MAX(score)OVER(PARTITION BY exam_id) max_x #求每类试卷的得分最大值
FROM exam_record a
LEFT JOIN examination_info b ON a.exam_id=b.exam_id
WHERE difficulty='hard' #难度为'hard'
AND score IS NOT NULL; #分数不为空

 

2)在每份试卷作答记录内执行min-max归一化

  • (score-min(score))/(max(score)-min(score))
  • 如果某个试卷作答记录中只有一个得分,那么无需使用公式,当min(score)=max(score)那就说明只有一个得分
  • 区间为[0-100],归一化结果*100

SELECT exam_id,uid,score,
	IF(min_x=max_x,score,(score-min_x)*100/(max_x-min_x))max_min #如果某试卷只有一个得分,不用公式
FROM (
		SELECT uid,a.exam_id,score,
		MIN(score) OVER(PARTITION BY exam_id) min_x, #求每类试卷的得分最小值
		MAX(score)OVER(PARTITION BY exam_id) max_x #求每类试卷的得分最大值
		FROM exam_record a
		LEFT JOIN examination_info b ON a.exam_id=b.exam_id
		WHERE difficulty='hard' #难度为'hard'
		AND score IS NOT NULL #分数不为空
	)t1


3)归一化后分数平均值取整数

  •  ROUND(SUM(max_min)/COUNT(max_min),0) avg_new_score

6)按照试卷ID升序、归一化分数降序输出。
ORDER BY exam_id,avg_new_score DESC
7)完整代码

SELECT uid,exam_id,
ROUND(SUM(max_min)/COUNT(max_min),0) avg_new_score
FROM (
	SELECT exam_id,uid,score,
	IF(min_x=max_x,score,(score-min_x)*100/(max_x-min_x))max_min/*如果某试卷只有一个得分*/
	FROM (
		SELECT uid,a.exam_id,score,
		MIN(score) OVER(PARTITION BY exam_id) min_x, #求每类试卷的得分最小值
		MAX(score)OVER(PARTITION BY exam_id) max_x #求每类试卷的得分最大值
		FROM exam_record a
		LEFT JOIN examination_info b ON a.exam_id=b.exam_id
		WHERE difficulty='hard' #难度为'hard'
		AND score IS NOT NULL #分数不为空
		)t1
		
	)t2

GROUP BY exam_id,uid
ORDER BY exam_id,avg_new_score DESC;#按照试卷ID升序,评价分降序排序