用MySQL计算中位数的简单方法

用MySQL计算中位数的最简单的方法(希望不是太慢)? 我用AVG(x)找到了平均值,但我很难找到一个计算中位数的简单方法。 现在,我将所有行返回给PHP,进行排序,然后选择中间行,但在一个MySQL查询中肯定有一些简单的方法。

示例数据:

id | val
--------
 1    4
 2    7
 3    2
 4    2
 5    9
 6    8
 7    3

val排序得到2 2 3 4 7 8 9 ,所以中位数应该是4 ,而SELECT AVG(val) = 5


建议的解决方案(TheJacobTaylor)的问题是运行时问题。 加入表格本身对于大型数据集来说太慢了。 我建议的替代方案在MySQL中运行,运行时非常棒,使用显式的ORDER BY语句,因此您不必希望索引为了给出正确的结果而正确命令它,并且很容易展开查询以进行调试。

SELECT avg(t1.val) as median_val FROM (
SELECT @rownum:=@rownum+1 as `row_number`, d.val
  FROM data d,  (SELECT @rownum:=0) r
  WHERE 1
  -- put some where clause here
  ORDER BY d.val
) as t1, 
(
  SELECT count(*) as total_rows
  FROM data d
  WHERE 1
  -- put same where clause here
) as t2
WHERE 1
AND t1.row_number in ( floor((total_rows+1)/2), floor((total_rows+2)/2) );

[edit]在(...)中添加avg()周围的t1.val和row_number,以便在存在偶数个记录时正确生成中位数。 推理:

SELECT floor((3+1)/2),floor((3+2)/2);#total_rows is 3, so avg row_numbers 2 and 2
SELECT floor((4+1)/2),floor((4+2)/2);#total_rows is 4, so avg row_numbers 2 and 3

我刚刚在评论中发现了另一个在线答案:

对于几乎任何SQL中的中值:

SELECT x.val from data x, data y
GROUP BY x.val
HAVING SUM(SIGN(1-SIGN(y.val-x.val))) = (COUNT(*)+1)/2

确保您的列的索引很好,并且索引用于过滤和排序。 验证解释计划。

select count(*) from table --find the number of rows

计算“中位数”行号。 也许使用: median_row = floor(count / 2)

然后从列表中选择它:

select val from table order by val asc limit median_row,1

这应该返回你一行,只是你想要的值。

雅各


我发现接受的解决方案不适用于我的MySQL安装,返回一个空集,但是这个查询在我测试过的所有情况下都适用于我:

SELECT x.val from data x, data y
GROUP BY x.val
HAVING SUM(SIGN(1-SIGN(y.val-x.val)))/COUNT(*) > .5
LIMIT 1
链接地址: http://www.djcxy.com/p/83819.html

上一篇: Simple way to calculate median with MySQL

下一篇: binding with 'with'?