Наиболее частое значение с группировкой по двум столбцам mysql - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть таблица (тест) с двумя столбцами (имя varchar (5), cnt int)

Имя таблицы: test

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

и имеют значения

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

Я пробовал запрос как

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

Но результат, который я получаю

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

здесь - sql fiddle ссылка

Ответы [ 6 ]

0 голосов
/ 20 февраля 2019

Я сам что-то сделал, но не уверен, что это эффективно.Поскольку моя таблица может иметь много записей.

select * from 
(select distinct name, cnt, COUNT(cnt) as count
from test
group by cnt, name
order by count desc) A
group by name
0 голосов
/ 20 февраля 2019

Если вы хотите сообщить все записи в случае ничьей

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)
0 голосов
/ 20 февраля 2019

Для поиска наиболее часто встречающегося значения можно использовать коррелированный запрос с LIMIT:

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
0 голосов
/ 20 февраля 2019

эта работа:

  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
0 голосов
/ 20 февраля 2019

попробуйте, как показано ниже, используя коррелированный подзапрос

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 на версию подзапроса

0 голосов
/ 20 февраля 2019

Вот один из способов сделать это с помощью оконных функций:

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;

enter image description here

Демо

Редактировать:

Вот моя попытка решения до 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;

Демо

Сложность заключается в том, что сначала нам нужно агрегировать как по name, так и cnt, чтобы найти максимальные значения для каждой группы.Затем необходимо выполнить запрос, чтобы найти группу для каждого name, имеющего наибольшее количество.Наконец, требуется другая агрегация, чтобы найти группу name с наименьшим значением 1033 * cnt, в случае, если у данного name есть две подгруппы с одинаковым количеством (например, * 1036).*).

...