题目描述:老师想知道学生们综合成绩的中位数是什么档位,请你写SQL帮忙查询一下,如果只有1个中位数,输出1个,如果有2个中位数,按grade升序输出。
个人思路:
步骤一、为各个grade添加排名取值范围(t_rank,section)。
步骤二、找出总共参与考试的学生人数(total)。
步骤三、找出中位数floor((t.total+1)/2)、floor((t.total+2)/2)在哪个名次的取值范围内。

 with t_rank as  #-- 添加排名作为取值区间的最大值
(
    select grade, 
           sum(number) over(order by grade)as sec_1
    from class_grade
),
section as #--完成取值区间 ,如 A ,0,2
(
    select grade,
           ifnull(lag(sec_1) over(),0) as sec_0,
           sec_1
    from t_rank
),
total as #--找出总名次数
(
    select sum(number)as total
    from class_grade
)
#--查询出出中位数在哪个名次的取值区间,获得grade
select s.grade 
from section s ,total t
where (floor((t.total+1)/2) > sec_0 and floor((t.total+1)/2) <= sec_1)
  or (floor((t.total+2)/2) > sec_0 and floor((t.total+2)/2) <= sec_1)
order by grade

IFNULL(v1,v2) 如果 v1 的值不为 NULL,则返回 v1,否则返回 v2。
窗口函数lag(sec_1) over() 获取上一行sec_1的值。
表section的结果:
grade sec_0 sec_1
A 0 2
B 2 4
C 4 6
D 6 7
注意的是,实际上每个名次的取值范围应该是左开右闭的区间即A(0,2},B(2,4}...。所以后面用中位数进行筛选时是>sec_0 and <=sec_1。

借鉴大佬的思路:

with t_rank as
(
    select grade,
       (select sum(number) from class_grade) as total,
       sum(number) over(order by grade) a,
       sum(number) over(order by grade desc) b
    from class_grade
    order by grade
)
select grade 
from t_rank
where a>=total/2 and b>=total/2
order by grade

t_rank找出名次,总数,正序排名和倒序排名。
然后找出正序排序大于一半的同时倒序也大于一半的(实际上这不就是中位数吗╮(╯▽╰)╭)
大佬神奇的思路,赞!! (๑•̀ㅂ•́)و✧