有没有一种更简单的方法可以在MySQL中找到某些值的MODE(S)

时间:2013-12-17 23:35:40

标签: mysql mode

MODE是数据中MOST次数发生的值,可以有一种模式或多种模式

这里有两个表格中的一些值(sqlFiddle

create table t100(id int auto_increment primary key, value int);
create table t200(id int auto_increment primary key, value int);

insert into t100(value) values (1),
                               (2),(2),(2),
                               (3),(3),
                               (4);
insert into t200(value) values (1),
                               (2),(2),(2),
                               (3),(3),
                               (4),(4),(4);

现在,为了让MODE(S)以逗号分隔列表的形式返回,我对表t100运行以下查询

     SELECT GROUP_CONCAT(value) as modes,occurs
     FROM
        (SELECT value,occurs FROM 
           (SELECT value,count(*) as occurs
            FROM
            T100
            GROUP BY value)T1,
        (SELECT max(occurs) as maxoccurs FROM 
            (SELECT value,count(*) as occurs
             FROM
             T100
             GROUP BY value)T2
        )T3
        WHERE T1.occurs = T3.maxoccurs)T4
      GROUP BY occurs;

以及表t200的以下查询(同一查询只更改了表名)我在此示例中有2个表,因为它表明它适用于存在1个MODE并且存在多个MODES的情况。< / p>

     SELECT GROUP_CONCAT(value) as modes,occurs
     FROM
        (SELECT value,occurs FROM 
           (SELECT value,count(*) as occurs
            FROM
            T200
            GROUP BY value)T1,
        (SELECT max(occurs) as maxoccurs FROM 
            (SELECT value,count(*) as occurs
             FROM
             T200
             GROUP BY value)T2
        )T3
        WHERE T1.occurs = T3.maxoccurs)T4
      GROUP BY occurs;

我的问题是“有更简单的方法吗?”

我在考虑使用HAVING count(*) = max(count(*))或类似的东西来摆脱额外的连接,但无法让HAVING返回我想要的结果。

更新: 正如@zneak所建议的那样,我可以简化T3,如下所示:

     SELECT GROUP_CONCAT(value) as modes,occurs
     FROM
        (SELECT value,occurs FROM 
           (SELECT value,count(*) as occurs
            FROM
            T200
            GROUP BY value)T1,
        (SELECT count(*) as maxoccurs
             FROM
             T200
             GROUP BY value
             ORDER BY count(*) DESC
             LIMIT 1
        )T3
        WHERE T1.occurs = T3.maxoccurs)T4
      GROUP BY occurs;

现在有办法完全驾驭T3吗? 我尝试了这个,但由于某种原因它没有返回任何行

  SELECT value,occurs FROM  
    (SELECT value,count(*) as occurs
     FROM t200
     GROUP BY `value`)T1
  HAVING occurs=max(occurs)  

基本上我想知道是否有办法做到这一点,我只需要指定t100t200一次。

更新:我找到了一种指定t100t200的方法,只需添加一个变量来设置我自己的maxoccurs,如下所示

  SELECT GROUP_CONCAT(CASE WHEN occurs=@maxoccurs THEN value ELSE NULL END) as modes 
  FROM 
    (SELECT value,occurs,@maxoccurs:=GREATEST(@maxoccurs,occurs) as maxoccurs
     FROM (SELECT value,count(*) as occurs
           FROM t200
           GROUP BY `value`)T1,(SELECT @maxoccurs:=0)mo
     )T2

1 个答案:

答案 0 :(得分:6)

您与上次查询非常接近。以下是一个模式:

SELECT value, occurs
FROM (SELECT value,count(*) as occurs
      FROM t200
      GROUP BY `value`
      LIMIT 1
     ) T1

我认为你的问题是关于多种模式,但是:

SELECT value, occurs
FROM (SELECT value, count(*) as occurs
      FROM t200
      GROUP BY `value`
     ) T1
WHERE occurs = (select max(occurs)
                from (select `value`, count(*) as occurs
                      from t200
                      group by `value`
                     ) t
               );

编辑:

这在几乎任何其他数据库中都要容易得多。 MySQL既不支持with也不支持窗口/分析功能。

您的查询(如下所示)不符合您的想法:

  SELECT value, occurs  
  FROM (SELECT value, count(*) as occurs
        FROM t200
        GROUP BY `value`
       ) T1
  HAVING occurs = max(occurs) ; 

最终having子句引用变量​​occurs,但确实使用max(occurs)。由于使用了max(occurs),这是一个返回一行的聚合查询,总结了子查询中的所有行。

变量occurs不用于分组。那么,MySQL使用什么价值呢?它使用子查询中某个行的任意值。此任意值可能匹配,也可能不匹配。但是,该值仅来自一行。它没有迭代。