方法一:使用聚合函数AVG()同时筛选相关条件即可
首先确定好条件为 difficulty = 'hard', tag = 'SQL', 同时需要把score等于!!! sql高难度!!!试卷得分的最大值最小值的数据去掉。
因为聚合函数AVG()会自动忽略值为null的行,所以不用担心它会把score为空值的行加到计算平均数的分母中去,也不用担心有没有重复值。
错解(感谢评论区指出!):
WHERE后面写如下的子查询,是把整个表的最大、最小的score查找出来,而不是 sql高难度试卷得分的最大值最小值了👇
SELECT tag, difficulty, ROUND(AVG(r.score), 1) AS clip_avg_score FROM exam_record r LEFT JOIN examination_info i USING(exam_id) WHERE difficulty = 'hard' AND tag = 'SQL' AND r.score NOT IN (SELECT MAX(score) FROM exam_record) AND r.score NOT IN (SELECT MIN(score) FROM exam_record);
更新解:
1. 先取得 sql高难度试卷得分的最大值最小值,再作为筛选条件加到主查询中
WITH max_min AS( SELECT exam_id, MAX(score) AS sql_hard_max_score, MIN(score) AS sql_hard_min_score FROM exam_record JOIN examination_info USING(exam_id) WHERE difficulty = 'hard' AND tag = 'SQL' GROUP BY exam_id ) SELECT tag, difficulty, ROUND(AVG(r.score), 1) AS clip_avg_score FROM exam_record r LEFT JOIN examination_info i USING(exam_id) WHERE difficulty = 'hard' AND tag = 'SQL' AND r.score != (SELECT sql_hard_max_score FROM max_min) AND r.score != (SELECT sql_hard_min_score FROM max_min) GROUP BY tag;
2.一步到位加到主查询中(如果有更简单的解法欢迎贴在评论区~
SELECT tag, difficulty, ROUND(AVG(r.score), 1) AS clip_avg_score FROM exam_record r LEFT JOIN examination_info i USING(exam_id) WHERE difficulty = 'hard' AND tag = 'SQL' AND r.score NOT IN (SELECT MAX(score) FROM exam_record WHERE exam_id IN(SELECT exam_id FROM examination_info WHERE difficulty = 'hard' AND tag = 'SQL')) AND r.score NOT IN (SELECT MIN(score) FROM exam_record WHERE exam_id IN(SELECT exam_id FROM examination_info WHERE difficulty = 'hard' AND tag = 'SQL')) GROUP BY tag;
我使用的是DENSE_RANK() OVER() 的窗口函数,其实大致思路和方法一差不多,就是把最大最小值从表中去掉。
利用DENSE_RANK()函数将表中的行按照score从低到高,从高到低分别排序编号,然后将排名为1的行都去掉,就得到去掉最大值最小值的表了,最后取数并且用AVG()求阶段平均值。
但是!!这个方法要注意一点就是要先把score为NULL的行去掉,因为如果不去掉它们,利用DENSE_RANK() 从低到高排序的时候,score为NULL是默认排在第一位的,排名为1,这样的话最小值其实是排名为2的,所以我们代码运行后去掉的其实是空值,和最大值,最后求出来的结果就是错误的!
SELECT tag, difficulty, ROUND(AVG(score), 1) AS clip_avg_score FROM (SELECT exam_id, tag, difficulty, score, DENSE_RANK() OVER(ORDER BY score) AS t_rank_a, DENSE_RANK() OVER(ORDER BY score DESC) AS t_rank_d FROM exam_record LEFT JOIN examination_info i USING(exam_id) WHERE difficulty = 'hard' AND tag = 'SQL' AND score IS NOT NULL) ri WHERE t_rank_a != 1 AND t_rank_d != 1 GROUP BY tag;