简体   繁体   中英

Most frequent value with group by two columns mysql

I have a table (test) with two columns (name varchar(5), cnt int)

Table Name: test

+--------+-------------+
| column |    type     |
+--------+-------------+
| name   | varchar (5) |
| cnt    | int         |
+--------+-------------+

and have values

+------+-----+
| name | cnt |
+------+-----+
| A    |   1 |
| A    |   1 |
| A    |   1 |
| A    |   2 |
| B    |   1 |
| B    |   2 |
+------+-----+

I like to get result of most frequent count with unique name

So the expected result will be

+------+------+-------+
| name | cnt  | count |
+------+------+-------+
| A    |    1 |     3 |
| B    |    1 |     1 |
+------+------+-------+

As A has two 1 and one 2 and B has one 1 and one 2

I tried the query like

select distinct name, cnt, COUNT(cnt) as count
from test
group by cnt, name
order by count desc

But the result I am getting

+------+------+-------+
| name | cnt  | count |
+------+------+-------+
| A    |    1 |     3 |
| A    |    2 |     1 |
| B    |    1 |     1 |
| B    |    2 |     1 |
+------+------+-------+

here is the sql fiddle link

A correlated query with LIMIT could be used to find the most occurring value:

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

Here is one way to do this using window functions:

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;

在此处输入图片说明

Demo

Edit:

Here is my attempt at a pre-MySQL 8+ solution:

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;

Demo

The difficulty here is that we first have to aggregate by both name and cnt , to find the max counts for each group. Then, this has to be subqueried to find the group for each name having the highest count. Finally, another aggregation is required to find the name group with the lowest cnt value, in the case that a given name happens to have two sub groups with the same count (eg B ).

If you want to report all entries in the event of a draw

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)

try like below using corelated subquery

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

As for B both frequency is same that's why both will come on output, You can change this cte to subquery version

this work:

  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

I did something myself But not sure its efficient to do. As My table might have lots of entry.

select * from 
(select distinct name, cnt, COUNT(cnt) as count
from test
group by cnt, name
order by count desc) A
group by name

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM