资讯动态

SQL示例:找综合成绩的中位数,3种解法对比

发布时间:2026/8/20 0:36:13 来源:尧图企业网站定制
本文分析了SQL287题目的三种解法该题要求找出学生成绩的中位数档位。第一种解法通过窗口函数计算累计排名利用区间判断高效定位中位数第二种解法显式生成排名区间逻辑清晰但稍显冗余第三种解法递归展开数据行直观但性能较差。对比显示第一种解法最适合生产环境第二种适合教学调试第三种仅适用于小数据量演示。建议面试使用第一种解法学习原理时可结合后两种方法理解。题目SQL287 最差是第几名(二)描述TM小哥和FH小妹在牛客大学若干年后成立了牛客SQL班班的每个人的综合成绩用A,B,C,D,E表示90分以上都是A80~90分都是B70~80分为C60~70为DE为60分以下假设每个名次最多1个人比如有2个A那么必定有1个A是第1名有1个A是第2名(综合成绩同分也会按照某一门的成绩分先后)。每次SQL考试完之后老师会将班级成绩表展示给同学看。现在有班级成绩表(class_grade)如下:gradenumberA2C4B4D2第1行表示成绩为A的学生有2个.......最后1行表示成绩为D的学生有2个老师想知道学生们综合成绩的中位数是什么档位请你写SQL帮忙查询一下如果只有1个中位数输出1个如果有2个中位数按grade升序输出以上例子查询结果如下:gradeBC解析:总体学生成绩排序如下:A, A, B, B, B, B, C, C, C, C, D, D总共12个数取中间的2个取67为:B,C三种解法对比这道题的核心是求有序序列的中位数所在档位关键在于处理总人数为奇/偶时中位数可能是一个或两个位置。下面详细分析三种实现方式并对比它们的思路、优缺点。一、题目理解原始数据gradenumberA2B4C4D2展开后序列按 grade 排序同 grade 内排名任意但整体升序textA, A, B, B, B, B, C, C, C, C, D, D总人数 12偶数中位数位置 第 6、7 个 → B 和 C。二、第一种实现正序累加 区间判断sqlWITH t1 AS ( SELECT grade, number, SUM(number) OVER (ORDER BY grade) AS cnt, -- 累计到当前grade的末尾位置 SUM(number) OVER () AS total FROM class_grade ) SELECT grade FROM t1 WHERE cnt - number CEIL((total 1) / 2) AND cnt FLOOR((total 1) / 2) ORDER BY grade;核心思路cnt当前 grade 最后一个学生的全局排名。cnt - number 1到cnt是当前 grade 的排名范围。(total1)/2是常见的中位数位置公式总人数total为奇数时比如 11 → (111)/2 6 → 第 6 个是中位数。偶数时比如 12 → (121)/2 6.5取 floor 和 ceil 得到第 6 和第 7。用cnt - number 中位数上限且cnt ≥ 中位数下限判断中位数位置落在哪个 grade 区间。优点逻辑清晰直接利用区间覆盖判断。效率高两次窗口函数一次过滤O(n)。通用性强直接处理奇偶情况。缺点公式(total1)/2对初学者稍不直观。需要理解cnt - number是区间前一个位置。三、第二种实现显式生成区间 条件匹配sqlWITH t1 AS ( SELECT grade, number, SUM(number) OVER (ORDER BY grade) AS cnt, SUM(number) OVER () AS sum_cnt FROM class_grade ), t2 AS ( SELECT grade, number, cnt AS end_1, LAG(cnt, 1, 0) OVER (ORDER BY grade) 1 AS start_1, FLOOR((sum_cnt 1) / 2) AS start, CEIL((sum_cnt 1) / 2) AS end FROM t1 ) SELECT grade FROM t2 WHERE start BETWEEN start_1 AND end_1 OR end BETWEEN start_1 AND end_1;核心思路start_1~end_1当前 grade 的排名区间。start和end中位数的两个位置偶数时不同奇数时相同。判断中位数的位置是否落在 grade 区间内。优点可读性强明确计算出每个 grade 的起止排名。调试方便可以把所有中间列输出人工核对位置。缺点略冗余多了一层 CTE且LAG处理边界需要1和默认值。性能稍差比第一种多一次窗口计算但差别很小。四、第三种实现递归展开 行号sqlWITH RECURSIVE nums AS ( SELECT 1 AS id UNION ALL SELECT id 1 FROM nums WHERE id (SELECT MAX(number) FROM class_grade) ), t1 AS ( SELECT grade, ROW_NUMBER() OVER (ORDER BY grade) AS rn, COUNT(1) OVER () AS cnt FROM class_grade m LEFT JOIN nums n ON m.number n.id ) SELECT DISTINCT grade FROM t1 WHERE rn BETWEEN FLOOR((cnt 1) / 2) AND CEIL((cnt 1) / 2);核心思路用递归 CTE 生成序号1 到最大 number。通过number n.id实现每个 grade 按数量展开成多行。对展开结果直接使用ROW_NUMBER()获得每个学生的全局序号。最后按中位数位置范围过滤。优点直观物理上还原了“展开后排序”的过程。易理解对不熟悉窗口函数区间的人友好。缺点性能差递归 笛卡尔积left join 条件非等值产生大量中间行。假设最大 number 1000总行数会膨胀到 sum(number) 级别。内存/时间开销大不适用于大表。递归限制某些数据库或严格环境可能限制递归深度。五、对比总结实现思路性能可读性推荐场景一区间覆盖判断高中通用首选生产环境二显式起止排名 条件匹配中高高教学、调试逻辑清晰三递归展开 行号低高仅小数据量或教学演示不适用于生产六、最终建议面试/笔试用第一种简洁高效。理解过程用第二种逐步推导。学习原理用第三种直观感受“展开”过程但要知道性能风险。实际 SQL 生产环境如 Hive、Spark SQL、MySQL 8.0强烈推荐第一种方式。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价