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_ids qui ont à la fois 1 et 3 tag_ids, 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_ids liste qui sont présents dans ce groupe. Comment puis-je faire?

Était-ce utile?

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top