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