9
votes

MySQL Sélectionnez le plus fréquent par groupe

Comment puis-je obtenir la catégorie la plus fréquente pour chaque balise dans MySQL? Idéalement, je voudrais simuler une fonction agrégée qui calculerait le Mode d'un colonne.

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


2 commentaires

Juste pensé que je mentionne quelques années plus tard et plus intelligente - ne pas organiser des tags comme celui-ci, il est un antimodèle. Utilisez une table many2many pour définir la relation entre les balises et les éléments. Cela dit, je veux encore, il y avait une fonction d'agrégation MODE dans MySQL.


Il n'y a pas besoin d'abréger truc à s dans la question. Dans ce cas, il rend plus difficile de repérer que appartient au S plutôt que t car ils sont tous les deux caractères simples.


5 Réponses :


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

4 commentaires

J'ai eu des difficultés à obtenir que ça va travailler. Il semblerait être préférable de faire une fonction globale most_frequant () .. Je vais voir si cela se trouve dans mon niveau de compétence ici ...


Désolé, j'ai mal compris votre schéma. J'ai pris une apparence de plus près et je me suis moqué d'une base de données de test afin que je puisse être sûr que la requête fonctionne. Essayez la version modifiée ci-dessus.


Cela semble fonctionner. C'est un peu difficile à avaler .. et il y a deux sous-sélectionnées au lieu d'un seul. Je souhaite qu'il n'y ait qu'une fonction globale intégrée signifie () ou quelque chose de :-p. Je pourrais probablement écrire cela en utilisant C en 5min.


Voir mon contenu supplémentaire après la ligne de séparateur.



4
votes
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 commentaires

Cela devrait être la bonne réponse. Il évite de rejoindre un groupe par requête et devrait être beaucoup plus efficace. Il fait un groupe célibataire par et la présente, marquant les rangées dont nous avons besoin, puis les filtres. Intelligent!



3
votes

(Edit: DESC oublié COMMANDEZ BYs)

Facile à faire avec une limite dans la sous-requête. Est-ce que MySQL ont encore la restriction no limit-en-sous-requêtes? Ci-dessous, par exemple en utilisant PostgreSQL est. P>

=> 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)


0 commentaires

1
votes

Ceci est pour des situations plus simples:

Sélectionnez Action, Compte (Action) comme actionCompte Du journal Groupe par action Commande de ActionCount Desc;


0 commentaires

0
votes

Voici une approche hacky à ce qui utilise le max code> global car il n'y a pas de mode fonction d'agrégation dans MySQL (ou fenêtrage fonctions, etc.) qui permettrait à ceci:

SELECT 
  tag, 
  max(concat(lpad(c, 20, '0'), category)) AS xmost_frequent_category
FROM (
    SELECT tag, category, count(*) AS c
    FROM tags INNER JOIN stuff using (id) 
    GROUP BY tag, category
) as grouped_cats 
GROUP BY tag;

+-------------+---------------------------+
| tag         | xmost_frequent_category   |
+-------------+---------------------------+
| automotive  | 00000000000000000001cat-8 |
| ba          | 00000000000000000001cat-8 |
| bamboo      | 00000000000000000009cat-8 |
| banana tree | 00000000000000000004cat-8 |
| bath        | 00000000000000000001cat-9 |
+-------------+---------------------------+


0 commentaires