2009-03-15 13 views
1

Je rencontre des problèmes avec une requête SQL délicate.Filtrage à partir de la table de jointure

Dans ma base de données MySQL, il y a les tables topics, tags et tags_topics pour les joindre. Je souhaite récupérer des sujets partageant les mêmes balises spécifiées. Par exemple, disons que j'ai 3 balises avec les identifiants 1, 2 et 3, je veux récupérer tous les sujets qui ont l'étiquette 1, 2 et 3 qui leur sont associés. Les sujets peuvent avoir d'autres balises, mais doivent avoir toutes les balises spécifiées.

Aidez-moi plz pense xD

EDIT: trouvé une solution en utilisant GROUP BY dans cette question: Fetching only rows that match all entries in a joined table (SQL) Si quelqu'un a une solution plus élégante, s'il vous plaît poster :)

Répondre

4

solution JOIN:

SELECT t.* 
FROM topics t 
JOIN tags_topics t1 ON (t.id = t1.topicId AND t1.tagId = 1) 
JOIN tags_topics t2 ON (t.id = t2.topicId AND t2.tagId = 2) 
JOIN tags_topics t3 ON (t.id = t3.topicId AND t3.tagId = 3) 

GROUP BY solution:

Notez que vous devez lister toutes t.* colonnes dans la clause GROUP BY, sauf si vous utilisez MySQL ou SQLite.

SELECT t.* 
FROM topics t JOIN tags_topics tt 
    ON (t.id = tt.topicId AND tt.tagId IN (1,2,3)) 
GROUP BY t.id, ... 
HAVING COUNT(*) = 3; 

solution sous-requête:

SELECT t.* 
FROM topics t 
WHERE t.id = ANY (SELECT topicId FROM tags_topics tt WHERE tt.tagId = 1) 
    AND t.id = ANY (SELECT topicId FROM tags_topics tt WHERE tt.tagId = 2) 
    AND t.id = ANY (SELECT topicId FROM tags_topics tt WHERE tt.tagId = 3); 

modification GROUP BY solution:

Simplifie GROUP BY clause en isolant la recherche dans un sous-requête.

SELECT t.* 
FROM topics t 
WHERE t.id IN (
    SELECT tt.topicId FROM tags_topics tt 
    WHERE tt.tagId IN (1,2,3)) 
    GROUP BY tt.id HAVING COUNT(*) = 3 
); 
+0

COUNT (*) doit être> 2, car les sujets peuvent également avoir d'autres tags. Merci pour toutes vos suggestions! Modifiez cela, et je le définirai comme la bonne réponse;) – finpingvin

+0

@finpingvin - les autres balises ne sont pas considérées dans l'instruction. Le COUNT (*) = 3 sera correct, tant qu'il n'y a pas de doublons dans la table de jonction –

+0

Oui, je suppose que tags_topics a une clé primaire sur {topicId, tagId}. Btw, j'ai édité la quatrième solution pour éviter une jointure dans la sous-requête, après avoir lu la solution de @Russ Cam. –

3
SELECT 
    topic_id 
FROM 
    tags_topics 
WHERE 
    tag_id IN (1,2,3) 
GROUP BY 
    topic_id 
HAVING 
    COUNT(*) > 2 /* or use COUNT(*) = 3 if you know that there cannot be duplicates in the junction table */ 
+1

+1 pour éviter la jointure, en utilisant uniquement la table d'intersection. Cela fournit les valeurs topic_id pertinentes, mais pas l'entité de sujet complète. –