问题描述:老师想知道学生们综合成绩的中位数是什么档位,请你写SQL帮忙查询一下,如果只有1个中位数,输出1个,如果有2个中位数,按grade升序输出,以上例子查询结果如下:
方案1:设立三个表,计算中位数表t,人数累积表s,人数表(人数前移)l
WITH t AS ( # 中位数表
SELECT CASE WHEN MOD(SUM(number),2) = 0
THEN SUM(number)/2 ELSE (SUM(number)+1)/2
END AS start_num,
CASE WHEN MOD(SUM(number),2) = 0
THEN (SUM(number)+2)/2 ELSE (SUM(number)+1)/2
END AS end_num
FROM class_grade
) ,
s AS ( # 人数累积表
SELECT grade,SUM(number) OVER(ORDER BY grade ASC) AS sum_num
FROM class_grade
ORDER BY grade ASC
) ,
l AS ( # 人数累积表的前移
SELECT t.grade,IFNULL(LAG(t.sum_num) OVER(ORDER BY t.grade ASC),0) AS up_num
FROM (SELECT grade,SUM(number) OVER(ORDER BY grade ASC) AS sum_num
FROM class_grade
ORDER BY grade ASC) t
)
SELECT l.grade
FROM l
INNER JOIN s
ON l.grade = s.grade
CROSS JOIN t
WHERE (t.start_num > l.up_num AND t.end_num <= s.sum_num)
OR (t.start_num > l.up_num AND t.start_num <= s.sum_num)
OR (t.end_num > l.up_num AND t.end_num <= s.sum_num)
ORDER BY l.grade ASC;思路讲解:
中位数表t求解出中位数(两个,令其为start_num,end_num)
人数累计表s计算出每个grade对应的人数最大值,作为中位数对比的区间上界
l表计算出每个grade对应的人数最小值,作为中位数对比的区间下界
(不推荐,太繁琐了)
方案2:采用SunburstRun 的很妙的解法,将ABCD对应人数正序倒序一起排序,同时满足正序和倒序数都大于整个数列个数的一半的数即为中位数。
大佬说得很清楚了,详情可查看https://blog.nowcoder.net/n/caaa953ea61049fdab7cd6a303a6e8ad?f=comment
这里我再还原一下代码
SELECT grade
FROM (
SELECT grade,(SELECT SUM(number) FROM class_grade ) as total,
SUM(number) OVER(ORDER BY grade ASC) AS rank_1,
SUM(number) OVER(ORDER BY grade DESC) AS rank_2
FROM class_grade
) t
WHERE total/2 <= rank_1 AND total/2 <= rank_2
ORDER BY grade ASC;方案3:采用多个子查询的嵌套
参考Karra
https://blog.nowcoder.net/n/f646857973ea4b48b8356c02f57830ad?f=comment
SELECT t2.grade
FROM (
SELECT *,(t.sum_num-t.number) AS t_num,SUM(number) OVER() AS total
FROM(SELECT *,SUM(number) OVER(ORDER BY grade ASC) AS sum_num
FROM class_grade) t
) t2
WHERE t2.total/2 BETWEEN t2.t_num AND t2.sum_num
京公网安备 11010502036488号