按两列分组的最频繁值mysql
我有一个名为varchar5,cnt int的表测试 表名:测试 而且有价值按两列分组的最频繁值mysql,mysql,group-by,distinct,Mysql,Group By,Distinct,我有一个名为varchar5,cnt int的表测试 表名:测试 而且有价值 +------+-----+ | name | cnt | +------+-----+ | A | 1 | | A | 1 | | A | 1 | | A | 2 | | B | 1 | | B | 2 | +------+-----+ 我喜欢使用唯一的名称获取最频繁计数的结果 因此,预期的结果将是 +------+------+-------+ | na
+------+-----+
| name | cnt |
+------+-----+
| A | 1 |
| A | 1 |
| A | 1 |
| A | 2 |
| B | 1 |
| B | 2 |
+------+-----+
我喜欢使用唯一的名称获取最频繁计数的结果
因此,预期的结果将是
+------+------+-------+
| name | cnt | count |
+------+------+-------+
| A | 1 | 3 |
| B | 1 | 1 |
+------+------+-------+
A有两个1和一个2,B有一个1和一个2
我试着这样问
选择不同的名称、cnt、COUNTcnt作为计数
从测试
按cnt、名称分组
按计数顺序描述
但是我得到的结果是
+------+------+-------+
| name | cnt | count |
+------+------+-------+
| A | 1 | 3 |
| A | 2 | 1 |
| B | 1 | 1 |
| B | 2 | 1 |
+------+------+-------+
以下是sql FIDLE这里有一种使用窗口函数实现此功能的方法:
WITH cte AS (
SELECT name, cnt, COUNT(*) AS count,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY COUNT(*) DESC, cnt) rn
FROM yourTable
GROUP BY name, cnt
)
SELECT name, cnt, count
FROM cte
WHERE rn = 1;
编辑:
以下是我对MySQL 8+之前的解决方案的尝试:
SELECT t1.name, MIN(t1.cnt), MAX(t1.count)
FROM
(
SELECT name, cnt, COUNT(*) AS count
FROM yourTable
GROUP BY name, cnt
) t1
INNER JOIN
(
SELECT name, MAX(count) AS max_count
FROM
(
SELECT name, cnt, COUNT(*) AS count
FROM yourTable
GROUP BY name, cnt
) t
GROUP BY name
) t2
ON t1.name = t2.name AND t1.count = t2.max_count
GROUP BY
t1.name;
这里的困难在于,我们首先必须按名称和cnt进行聚合,以找到每组的最大计数。然后,必须对其进行子查询,以查找每个具有最高计数的名称的组。最后,如果给定名称恰好有两个具有相同计数的子组,例如B,则需要另一个聚合来查找具有最低cnt值的名称组。请使用相关子查询尝试下面的方法
WITH yourTable AS (
SELECT 'A' AS name, 1 AS cnt UNION ALL
SELECT 'A', 1 UNION ALL
SELECT 'A', 1 UNION ALL
SELECT 'A', 2 UNION ALL
SELECT 'B', 1 UNION ALL
SELECT 'B', 2
),
cte2 as (
select name, cnt, COUNT(*) as cn
from yourTable
group by cnt, name
) select t1.* from cte2 t1 where t1.cn=( select max(cn) from cte2 t2
where t2.name=t1.name
)
name cnt cn
A 1 3
B 1 1
B 2 1
对于B,两个频率相同,这就是为什么两个都会出现在输出上,您可以将此cte更改为子查询版本
SELECT a.name,a.cnt,max(a.count) AS count FROM (
SELECT distinct name, cnt, COUNT(cnt) as count
FROM test
GROUP BY name,cnt
) a
GROUP BY a.name
ORDER BY a.count DESC
具有限制的相关查询可用于查找最常出现的值:
SELECT name, cnt, COUNT(*) AS c
FROM t
WHERE cnt = (
SELECT cnt
FROM t AS x
WHERE name = t.name
GROUP BY cnt
ORDER BY COUNT(*) DESC
LIMIT 1
)
GROUP BY name, cnt
如果要在绘图时报告所有条目
select name,cnt,obs
from
(
select s.name,s.cnt,obs ,
if(s.name <>@pname, @rn:=1,if(s.obs<>@pobs,@rn:=@rn+1,@rn:=@rn)) denserank,
@pname:=s.name,
@pobs:=s.obs
from
(
select t.name, t.cnt,count(*) obs
from t
group by t.name,t.cnt
) s
) t
where denserank = 1;
+------+------+-----+
| name | cnt | obs |
+------+------+-----+
| A | 1 | 3 |
| B | 1 | 1 |
| B | 2 | 1 |
+------+------+-----+
3 rows in set (0.03 sec)
我自己做了一些事情,但不确定这是否有效。因为我的表可能有很多条目
select * from
(select distinct name, cnt, COUNT(cnt) as count
from test
group by cnt, name
order by count desc) A
group by name
A有3个1和1个2?如果B有一个1和一个2,为什么只显示1计数?你可能需要密集排名你使用的是哪个版本的mysql?抱歉,我在发布这个问题时额外添加了一行。我调整了answer@P.Salmonmysql版本14.14发行版5.7.19,对于Linux x86\u 64b,1和2看起来是一样的frequent@fa06你的评论根本不属于这里。@TimBiegeleisen,oppssorry@Atiq我已经给了你一个可以在你的MySQL版本上使用的选项。你的相关限制子查询有一个微妙的潜在问题。在出现平局(如B)的情况下,当前似乎会为每个名称组选择具有最大计数的较低cnt值。但这一点无法保证,至少不能仅基于SQL。我可以想到其他数据库,例如Postgres,您的查询可能会产生不正确的结果。OP没有提到如果计数相等会发生什么。RDBMS可以自由选择任何一种。但通过显式修改顺序很容易打破僵局,例如按计数*DESC、cnt排序-首选较小的值。良好保存+1。我喜欢你的答案胜过我的MySQL 5答案。但行数方法可能是最简单、最容易理解的方法。此查询无效,因为您在名称的外部查询中使用GROUP BY,但随后选择的是非聚合列。@TimBiegeleisen是否对其进行了测试?在MySQL的某些版本上。因此,您不应该将此作为推荐给其他人。您当前的输出与OP预期的不匹配。OP希望每个姓名都有一条记录,而不是2条。重新阅读问题。OP要求每个名称对应一行,而不是两行。但这是对会话变量的大胆使用,所以我将投票支持你。
select * from
(select distinct name, cnt, COUNT(cnt) as count
from test
group by cnt, name
order by count desc) A
group by name