Mysql 选择属性的SQL是什么?相关属性的最大出现次数是多少?

Mysql 选择属性的SQL是什么?相关属性的最大出现次数是多少?,mysql,Mysql,我有一张这样的桌子: Table: p +----------------+ | id | w_id | +---------+------+ | 5 | 8 | | 5 | 10 | | 5 | 8 | | 5 | 10 | | 5 | 8 | | 6 | 5 | | 6 | 8 | | 6 | 10 | | 6 | 10 | |

我有一张这样的桌子:

Table: p
+----------------+
| id      | w_id |
+---------+------+
| 5       |  8   |
| 5       | 10   |
| 5       |  8   |
| 5       | 10   |
| 5       |  8   |
| 6       |  5   |
| 6       |  8   |
| 6       | 10   |
| 6       | 10   |
| 7       |  8   |
| 7       | 10   |
+----------------+
获得以下结果的最佳SQL是什么

+-----------------------------+
| id      | most_used_w_id    |
+---------+-------------------+
|  5      |  8                |
|  6      | 10                |
|  7      |  8                |
+-----------------------------+
换句话说,根据id获取最频繁的相关w_id。 注意,在上面的示例中,id 7一次与8相关,一次与10相关。 因此,7,8或7,10都可以作为结果。如果不可能 选择一个,然后结果集上的7、8和7、10都可以

我想出了一些类似于:

select counters2.p_id as id, counters2.w_id as most_used_w_id
from (
  select p.id as p_id, 
         w_id,
         count(w_id) as count_of_w_ids
  from p
  group by id, w_id
) as counters2

join (
  select p_id, max(count_of_w_ids) as max_counter_for_w_ids
  from (
    select p.id as p_id, 
           w_id,
           count(w_id) as count_of_w_ids
    from p
    group by id, w_id
  ) as counters
  group by p_id
 ) as p_max 

on p_max.p_id = counters2.p_id
   and p_max.max_counter_for_w_ids = counters2.count_of_w_ids
;
但我完全不确定这是否是最好的方法。我不得不重复同样的子查询两次

有更好的解决方案吗?

试试这个查询

select p_id, ccc , w_id from
(
select p.id as p_id, 
         w_id, count(w_id) ccc
  from p
  group by id,w_id order by id,ccc desc) xxx
group by p_id having max(ccc)
这里是链接

如果不希望依赖非分组列的第一条记录,也可以使用此代码

select p_id, ccc , w_id from
(
select p.id as p_id, 
         w_id, count(w_id) ccc
  from p
  group by id,w_id order by id,ccc desc) xxx
group by p_id having ccc=max(ccc);
尝试使用

形式化SQL

事实上,就普通SQL而言,您的解决方案是正确的。为什么?因为您必须坚持将值从原始数据连接到分组数据。因此,您的查询无法简化。MySQL允许混合使用非组列和组函数,但这是完全不可靠的,所以我不建议您依赖这种效果

MySQL

因为您使用的是MySQL,所以可以使用变量。我不太喜欢它们,但对于你来说,它们可以用来简化事情:

SELECT 
  c.*, 
  IF(@id!=id, @i:=1, @i:=@i+1) AS num, 
  @id:=id AS gid 
FROM 
  (SELECT id, w_id, COUNT(w_id) AS w_count 
  FROM t 
  GROUP BY id, w_id 
  ORDER BY id DESC, w_count DESC) AS c
  CROSS JOIN (SELECT @i:=-1, @id:=-1) AS init
HAVING 
  num=1;
因此,对于您的数据,结果如下所示:

+------+------+---------+------+------+ | id | w_id | w_count | num | gid | +------+------+---------+------+------+ | 7 | 8 | 1 | 1 | 7 | | 6 | 10 | 2 | 1 | 6 | | 5 | 8 | 3 | 1 | 5 | +------+------+---------+------+------+ 这样,您就找到了您的id和相应的w_id。其思想是——计算行数并枚举它们,注意我们在子查询中对它们进行排序。所以我们只需要第一行,因为它将表示计数最高的数据

这可能会被id为单组的情况所取代,但同样,服务器可以自由选择任何一行,在这种情况下,它将工作,因为它将占用第一行,但文档中并没有对常见情况下的这一点进行说明

一个很好的地方是,你可以选择,例如,频率第二或第三,这是非常灵活的

演出

为了提高性能,您可以在id上创建索引,w_id-显然,它将用于对记录进行排序和分组。但是,变量和have会对set进行逐行扫描,由内部groupby派生。这并不像对原始数据进行完全扫描那样糟糕,但对变量进行扫描仍然不是一件好事。另一方面,在查询中使用JOIN&subquery这样做不会有太大的不同,因为也会为子查询结果集创建临时表


但可以肯定的是,你必须进行测试。请记住,您已经有了有效的解决方案,顺便说一句,该解决方案没有绑定到DBMS特定的东西,并且在通用SQL方面是好的。

最简单,但正如我所提到的,它是不正确的。你们不能相信事实,MySQL将获得第一条记录。在混合非组列时,可以自由选择任何行。当此fit OP请求时,我看不出它如何回答问题本身,即它到底是如何更好和更好why@AlmaDo:性能不仅取决于查询,还取决于表结构、索引、数据分布等,。。。所以OP应该在他的数据上尝试一下,然后决定哪一个更好。您的表没有主键。这是一个问题。然而,把这放在一边,这是一个很好的解决方案。它写得和我写的一模一样-您需要在解决方案中用p替换t。 +------+------+---------+------+------+ | id | w_id | w_count | num | gid | +------+------+---------+------+------+ | 7 | 8 | 1 | 1 | 7 | | 6 | 10 | 2 | 1 | 6 | | 5 | 8 | 3 | 1 | 5 | +------+------+---------+------+------+