使用MySQL计算中位数:STATION表LAT_N中位数查询报错求助
问题排查与正确解法
原代码的核心错误
- 外层查询逻辑冗余:你用
FROM STATION会返回表中所有行,但中位数是单一统计值,不需要遍历所有行输出,这会导致重复计算且结果混乱。 - 偶数行偏移量计算完全错误:你写的
(COUNT(LAT_N) / 2) + ((COUNT(LAT_N) + 2) / 2)会得出远大于总行数的偏移值,比如总行数为4时,计算结果是2+3=5,超出数据范围,直接触发报错或无结果。 - 子查询重复执行:外层每一行都会触发CASE里的子查询,完全没必要,还会严重拖慢查询效率。
正确解法(两种常用方案)
方案1:窗口函数法(兼容MySQL 8.0+、PostgreSQL等多数现代数据库)
用窗口函数精准定位中间行,无论行数奇偶都能正确计算中位数:
SELECT ROUND(AVG(LAT_N), 4) AS median_lat FROM ( SELECT LAT_N, ROW_NUMBER() OVER (ORDER BY LAT_N) AS row_num, COUNT(*) OVER () AS total_rows FROM STATION WHERE LAT_N IS NOT NULL -- 排除空值,保证计算准确 ) AS sub WHERE row_num IN (FLOOR((total_rows + 1)/2), CEIL((total_rows + 1)/2));
逻辑说明:先给每行按LAT_N排序并标出行号,同时统计总行数;再筛选出中间的1行(奇数行)或2行(偶数行),最后取平均值得到中位数并保留4位小数。
方案2:LIMIT OFFSET法(适配MySQL 5.x等不支持窗口函数的版本)
先统计总行数,再根据奇偶性分别处理:
SET @total = (SELECT COUNT(LAT_N) FROM STATION WHERE LAT_N IS NOT NULL); SET @mid = FLOOR((@total + 1)/2); SELECT ROUND( CASE WHEN @total % 2 = 1 THEN (SELECT LAT_N FROM STATION WHERE LAT_N IS NOT NULL ORDER BY LAT_N LIMIT 1 OFFSET @mid - 1) ELSE (SELECT AVG(LAT_N) FROM (SELECT LAT_N FROM STATION WHERE LAT_N IS NOT NULL ORDER BY LAT_N LIMIT 2 OFFSET @mid - 1) AS sub) END, 4 ) AS median_lat;
逻辑说明:先定义总行数和中间位置变量;奇数行直接取中间位置的数值,偶数行取中间两个数的平均值,最后保留4位小数。
关键注意点
必须排除LAT_N为空的行,否则会直接影响中位数计算的准确性。
内容的提问来源于stack exchange,提问作者KUSHAGRA ROHELA
相关产品推荐
相关产品推荐

