看了几个大佬写的题解,确实都很厉害,在这里我再提出一种新的解法(因为当初看题解的时候自己其实已经做到最后一步了,就想花点时间去按照自己的思路写出来,不想半途放弃o(╥﹏╥)o)
1 首先还是利用 sum() over()窗口函数求出各等级最差排名
select grade,number,sum(number) over(order by grade) max_rank
from class_grade
2 用 最差排名-此等级人数+1 可得到此等级最好排名
select a.grade,a.number,a.max_rank-a.number+1 min_rank,max_rank
from(select grade,number,sum(number) over(order by grade) max_rank
from class_grade) a
按照我本来的思路我是准备用上面的结果跟(得到的中位数:偶数则2个,奇数则1个)进行非等值连接 between min_rank and max_rank 来选出中位数所在的等级。本来想用 case when 或者if 来做,但是我发现 case when then的后面好像接不了两个值(就比如偶数的时候需要返回2个中位数),然后我就想能不能在when的后面和then的后面放查询语句,发现也不行,最后没办法了突然想到查两次,然后根据联合查询union的去重作用(union all 不去重)写两个查询,偶数的时候对应不同的返回 代码如下:
SELECT
case sum(number)%2
when 0 then sum(number)/2
ELSE floor((sum(number)+1)/2)
END mid_grade
FROM class_grade
UNION
SELECT
case sum(number)%2
when 0 then sum(number)/2+1
ELSE floor((sum(number)+1)/2)
END
FROM class_grade
最后两表进行连接得到最终结果:
select b.grade
from(
select a.grade,a.number,a.max_rank-a.number+1 min_rank,max_rank
from(
select grade,number,sum(number) over(order by grade) max_rank
from class_grade) a) b
right join(
SELECT
case sum(number)%2
when 0 then sum(number)/2
ELSE
floor((sum(number)+1)/2)
END mid_grade
FROM class_grade
UNION
SELECT
case sum(number)%2
when 0 then sum(number)/2+1
ELSE
floor((sum(number)+1)/2)
END
FROM class_grade) c
on c.mid_grade between b.min_rank and b.max_rank
order by b.grade;