【问题标题】:SQL - Calculating median without sortingSQL - 计算中位数而不排序
【发布时间】:2017-07-24 20:28:30
【问题描述】:

我有一个包含一列整数值的 SQL 表,我想在不进行任何排序的情况下找到这些值的中位数。我首先尝试查找表中大于和小于每个值的数字:

SELECT DISTINCT d1.v,       
  (SELECT COUNT(d2.v)
   FROM Values d2  
   WHERE d2.v > d1.v
   ) AS greater_than,
   (SELECT COUNT(d2.v)
   FROM Values d2  
   WHERE d2.v < d1.v
   ) AS less_than
FROM Values d1

我不确定如何继续。我相信我想要上表中的值,其中greater_thanless_than 都等于num_entries / 2,但这仅适用于具有偶数条目的表。从我上面得到中位数的好方法是什么?

【问题讨论】:

  • 是的,我相信您需要添加某种案例工作,具体取决于表中条目数的奇偶性。
  • MySQLSQL-Server,是哪一个?
  • 只是想知道,为什么要这样做而不进行排序?
  • 如果可能有重复值,这也不起作用。示例:[1, 1, 2]
  • @waka 它是MySQL。抱歉,我已经更改了标签。

标签: mysql median


【解决方案1】:

你可以这样做:

SELECT (MIN(v)+MAX(v))/2
FROM   (
        SELECT  CASE WHEN
                        LEAST((SELECT COUNT(*) FROM tbl WHERE v <= d1.v),
                              (SELECT COUNT(*) FROM tbl WHERE v >= d1.v))
                           >= (SELECT COUNT(*)/2 FROM tbl) 
                     THEN v
                END as v
        FROM    tbl d1
       ) as sub

内部查询保证在可能的许多 null 值中返回 1 或 2 个不同的非 null 值。非null 的值可能会重复,但通过取最小值和最大值,这两个值可用于计算中位数。

注意:不要将您的表命名为Values:这是一个保留字。

【讨论】:

  • 但是GROUP BY 要么对表格进行排序,要么使用已经排序的索引 :-)
  • 是的,不幸的是,正如@PaulSpiegel 指出的那样,有效的解决方案不能使用任何排序。
  • @user6269144 请注意,DISTINCT 也会使用某种排序,因此您的原始尝试也将是“无效的”。
  • @PaulSpiegel 是的,但它只是为了清晰起见。最坏的情况,它被删除了,我的最终答案给出了多个“相同”的中位数值,这是可以接受的。
  • 我用不使用group bydistinct 的版本更新了我的答案。
【解决方案2】:

查找大于和小于等于总行数/2 的自身数的总数。

create table med(id integer);
insert into med(id) values(1);
insert into med(id) values(2);
insert into med(id) values(3);
insert into med(id) values(4);
insert into med(id) values(5);
insert into med(id) values(6);

select (MIN(count)+MAX(count))/2 from 
(select case when (select count(*) from 
med A where A.id<B.id)=(select count(*)/2 from med) OR 
(select count(*) from med A where A.id>B.id)=(select count(*)/2 
from med) then cast(B.id as float)end as count from med B) C;

 ?column? 
----------
  3.5
(1 row)

你需要强制转换为浮点数,否则你会在这里得到 3。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 2016-04-04
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 2013-04-03
    • 2016-03-02
    相关资源
    最近更新 更多