/ / MySQL SELECT найчастіше за групою - mysql, group-by, найбільше-n-групи, частота

MySQL SELECT найчастіше за групами - mysql, група, найбільша-n-per-group, частота

Як отримати найбільш часто зустрічається категорію для кожного тегу в MySQL? В ідеалі, я хотів би імітувати сукупну функцію, яка б обчислила режим колонки.

SELECT
t.tag
, s.category
FROM tags t
LEFT JOIN stuff s
USING (id)
ORDER BY tag;

+------------------+----------+
| tag              | category |
+------------------+----------+
| automotive       |        8 |
| ba               |        8 |
| bamboo           |        8 |
| bamboo           |        8 |
| bamboo           |        8 |
| bamboo           |        8 |
| bamboo           |        8 |
| bamboo           |       10 |
| bamboo           |        8 |
| bamboo           |        9 |
| bamboo           |        8 |
| bamboo           |       10 |
| bamboo           |        8 |
| bamboo           |        9 |
| bamboo           |        8 |
| banana tree      |        8 |
| banana tree      |        8 |
| banana tree      |        8 |
| banana tree      |        8 |
| bath             |        9 |
+-----------------------------+

Відповіді:

3 для відповіді № 1
SELECT t1.*
FROM (SELECT tag, category, COUNT(*) AS count
FROM tags INNER JOIN stuff USING (id)
GROUP BY tag, category) t1
LEFT OUTER JOIN
(SELECT tag, category, COUNT(*) AS count
FROM tags INNER JOIN stuff USING (id)
GROUP BY tag, category) t2
ON (t1.tag = t2.tag AND (t1.count < t2.count
OR t1.count = t2.count AND t1.category < t2.category))
WHERE t2.tag IS NULL
ORDER BY t1.count DESC;

Я погоджуюся, що це занадто багато для одного запиту SQL. Будь-яке використання GROUP BY всередині підзапиту змушує мене здригнутися. Ви можете зробити це дивись простіше за допомогою переглядів:

CREATE VIEW count_per_category AS
SELECT tag, category, COUNT(*) AS count
FROM tags INNER JOIN stuff USING (id)
GROUP BY tag, category;

SELECT t1.*
FROM count_per_category t1
LEFT OUTER JOIN count_per_category t2
ON (t1.tag = t2.tag AND (t1.count < t2.count
OR t1.count = t2.count AND t1.category < t2.category))
WHERE t2.tag IS NULL
ORDER BY t1.count DESC;

Але це в основному робить ту ж саму роботу за лаштунками.

Ви коментуєте, що ви можете легко виконати подібну операцію в коді програми. Так чому б не зробити це? Зробіть більш простий запит, щоб отримати підрахунок для кожної категорії:

SELECT tag, category, COUNT(*) AS count
FROM tags INNER JOIN stuff USING (id)
GROUP BY tag, category;

І сортуйте результат у коді програми.


3 для відповіді № 2

(Редагувати: забули DESC у ORDER BYs)

Легко зробити з LIMIT у підзапиті. Чи існує у MySQL обмеження no-LIMIT-in-subqueries? Нижче наведено приклад використання PostgreSQL.

=> select tag, (select category from stuff z where z.tag = s.tag group by tag, category order by count(*) DESC limit 1) AS category, (select count(*) from stuff z where z.tag = s.tag group by tag, category order by count(*) DESC limit 1) AS num_items from stuff s group by tag;
tag     | category | num_items
------------+----------+-----------
ba         |        8 |         1
automotive |        8 |         1
bananatree |        8 |         4
bath       |        9 |         1
bamboo     |        8 |         9
(5 rows)

Третій стовпець необхідний тільки, якщо вам потрібний підрахунок.


2 для відповіді № 3
SELECT  tag, category
FROM    (
SELECT  @tag <> tag AS _new,
@tag := tag AS tag,
category, COUNT(*) AS cnt
FROM    (
SELECT  @tag := ""
) vars,
stuff
GROUP BY
tag, category
ORDER BY
tag, cnt DESC
) q
WHERE   _new

На ваших даних буде повернуто наступне:

"automotive",  8
"ba",          8
"bamboo",      8
"bananatree",  8
"bath",        9

Сценарій тесту:

CREATE TABLE stuff (tag VARCHAR(20) NOT NULL, category INT NOT NULL);

INSERT
INTO    stuff
VALUES
("automotive",8),
("ba",8),
("bamboo",8),
("bamboo",8),
("bamboo",8),
("bamboo",8),
("bamboo",8),
("bamboo",10),
("bamboo",8),
("bamboo",9),
("bamboo",8),
("bamboo",10),
("bamboo",8),
("bamboo",9),
("bamboo",8),
("bananatree",8),
("bananatree",8),
("bananatree",8),
("bananatree",8),
("bath",9);

1 для відповіді № 4

Це для більш простих ситуацій:

SELECT action, COUNT(action) AS ActionCount FROM log GROUP BY action ORDER BY ActionCount DESC;