Utiliser IN :
SELECT p.*
FROM POSTS p
WHERE p.id IN (SELECT tg.post_id
FROM TAGGINGS tg
JOIN TAGS t ON t.id = tg.tag_id
WHERE t.name IN ('Cheese','Wine','Paris','Frace','City','Scenic','Art')
GROUP BY tg.post_id
HAVING COUNT(DISTINCT t.name) = 7)
Utiliser une jointure
SELECT p.*
FROM POSTS p
JOIN (SELECT tg.post_id
FROM TAGGINGS tg
JOIN TAGS t ON t.id = tg.tag_id
WHERE t.name IN ('Cheese','Wine','Paris','Frace','City','Scenic','Art')
GROUP BY tg.post_id
HAVING COUNT(DISTINCT t.name) = 7) x ON x.post_id = p.id
Utiliser EXISTE
SELECT p.*
FROM POSTS p
WHERE EXISTS (SELECT NULL
FROM TAGGINGS tg
JOIN TAGS t ON t.id = tg.tag_id
WHERE t.name IN ('Cheese','Wine','Paris','Frace','City','Scenic','Art')
AND tg.post_id = p.id
GROUP BY tg.post_id
HAVING COUNT(DISTINCT t.name) = 7)
Explication
L'essentiel est que le COUNT(DISTINCT t.name)
doit correspondre au nombre de noms de balises pour s'assurer que toutes ces balises sont liées à la publication. Sans le DISTINCT, il y a un risque que les doublons de l'un des noms renvoient un nombre de 7 - vous auriez donc un faux positif.
Performances
La plupart vous diront que le JOIN est optimal, mais les JOIN risquent également de dupliquer des lignes dans le jeu de résultats. EXISTS serait mon prochain choix - pas de risque de duplication et une exécution généralement plus rapide, mais la vérification du plan d'explication vous indiquera finalement ce qui est le mieux en fonction de votre configuration et de vos données.