Mysql: comment sélectionner des groupes ayant certaines valeurs?
Question
Dire qu'il ya ce tableau:
mysql> SELECT * FROM tags;
+---------+--------+
| post_id | tag_id |
+---------+--------+
| 1 | 2 |
| 1 | 3 |
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
+---------+--------+
5 rows in set (0.00 sec)
Les noms de champ sont assez explicites. Je veux choisir post_id
s qui ont à la fois 1 et 3 tag_id
s, donc dans cet exemple, il est seulement 1
. Je pensais à quelque chose comme
SELECT post_id FROM tags GROUP BY post_id HAVING ...
Après avoir, je voudrais tag_id
s liste qui sont présents dans ce groupe. Comment puis-je faire?
La solution
S'il n'y a pas de contraintes uniques essayer:
SELECT post_id
FROM tags
WHERE tag_id = 1 OR tag_id = 3
GROUP BY post_id
HAVING count(DISTINCT tag_id) = 2;
Ou utiliser cette clause de HAVING
, si vous essayez de détecter seulement deux valeurs tag_id
:
HAVING MIN(tag_id) <> MAX(tag_id)
Si post_id et tag_id les deux ont une contrainte unique, cela devrait fonctionner aussi:
SELECT post_id
FROM tags
WHERE tag_id = 1 OR tag_id = 3
GROUP BY post_id
HAVING count(*) = 2;
Autres conseils
Vous pouvez essayer une auto join (N tag_id -> N join) mais probablement ce n'est pas rapide
SELECT t1.post_id
FROM tags t1 INNER JOIN tags t2 ON t1.post_id = t2.post_id
WHERE t1.tag_id = 1 AND t2.tag_id = 3
Je l'ai fait quelques hypothèses sur vos autres tables. (À savoir que vous avez une table pour les postes que j'ai appelé posts
et une avec tag_id comme PK que j'ai appelé tag_table
pour éviter un nameclash avec les messages / balises table, je vous vois déjà appel tags
)
Vous voulez des postes où il n'existe pas une balise dans la liste {1,3} pour laquelle il n'existe pas un enregistrement correspondant avec le correspondant post_id / tag_id de sorte que vous pouvez utiliser un double NOT EXISTS construction comme ci-dessous.
SELECT post_id
FROM posts p
WHERE NOT EXISTS
(SELECT * FROM tag_table tt
WHERE tag_id IN (1,3)
AND NOT EXISTS
(SELECT * FROM tags t
WHERE t.tag_id = tt.tag_id and
p.post_id = t.post_id)
)
Une autre méthode consiste à utiliser Grouper par et le comte. A examen des approches de ce problème est ici .
SELECT post_id
FROM ( SELECT post_id,
count(tag_id) AS counter
FROM tags
WHERE tag_id IN (1,3)
GROUP BY post_id
)
WHERE counter = 2
Utilisez GROUP_CONCAT () pour la deuxième partie de votre question
SELECT post_id,
GROUP_CONCAT(tag_id ORDER BY tag_id ASC SEPARATOR ',')
FROM tags
Qu'en est-
SELECT *
FROM tags
WHERE post_id in
(SELECT post_id AS pid
FROM tags
WHERE 1 IN (SELECT tag_id FROM tags WHERE post_id = pid)
AND 3 IN (SELECT tag_id FROM tags WHERE post_id = pid)
);
WHERE version de @ solution Keeper
SELECT DISTINCT t1.post_id
FROM tags t1, tags t2
WHERE
t1.post_id = t2.post_id AND
t1.tag_id = 1 AND t2.tag_id = 3