题目描述:老师想知道学生们综合成绩的中位数是什么档位,请你写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 gradeIFNULL(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 gradet_rank找出名次,总数,正序排名和倒序排名。
然后找出正序排序大于一半的同时倒序也大于一半的(实际上这不就是中位数吗╮(╯▽╰)╭)
大佬神奇的思路,赞!! (๑•̀ㅂ•́)و✧

京公网安备 11010502036488号