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 | +------+------+---------+------+------+