2010-08-03 4 views
2

Si j'ai une relation plusieurs à plusieurs entre les publications et les tags, comment puis-je sélectionner les publications qui contiennent un tag spécifique?SQL Comment puis-je interroger une relation plusieurs à plusieurs

mise à jour:

le problème que j'ai est qu'en raison de la tag.name = 'xxx' où, seule cette balise est sélectionnée. ce que je veux est de sélectionner tous les messages qui ont le tag spécifié, tgt avec tous leurs tags, par exemple.

Post 1 -> tag1, tag2 
Post 2 -> tag1, tag3 
Post 3 -> tag2, tag3 

actuellement ce que je reçois est

Post 1 -> tag2 // missing tag1 
Post 3 -> tag2 // missing tag3 
+0

voir la mise à jour .... – cletus

+5

Étant donné que la réponse sélectionnée semble être une solution SQL par opposition à DQL, le titre de cette question ne devrait-il pas être changé de DQL en SQL? Je suis venu ici à la recherche d'un moyen de faire une requête DQL many-to-many, mais il n'y a rien ici. –

Répondre

4

En supposant que ces tables:

  • Messages: id, auteur, date, contenu
  • Tags: id, nom
  • PostTags : post_id, tag_id

La dernière table est souvent appelée join table et facilite une relation many-to-many entre Posts et Tags.

SELECT p.* 
FROM posts p 
JOIN posttags pt ON p.id = pt.post_id 
JOIN tags t ON pt.tag_id = t.id 
WHERE t.name = 'sql' 

En fait, pensez à plusieurs-à-plusieurs en deux un à plusieurs relations, parce que c'est la façon dont ils sont mis en œuvre dans le SGBDR normal. La requête ci-dessus a donc une jointure un-à-plusieurs de Posts à PostTags et une autre de Tags à PostTags. La table PostTags que j'ai créée a une clé primaire composite , soit (post_id, tag_id). Cette combinaison sera unique. Beaucoup défavoriser clés composites de sorte que vous verrez souvent des gens en créant une colonne de clé primaire:

  • PostTags: id, post_id, tag_id

ou l'autre méthode est très bien. C'est en grande partie une différence philosophique.

Mise à jour: si vous voulez sélectionner tous les messages qui ont une étiquette particulière et toutes les balises ces postes ont alors:

SELECT p.* 
FROM posts p 
JOIN posttags pt ON p.id = pt.post_id 
JOIN tags t ON pt.tag_id = t.id 
WHERE p.id IN 
    (SELECT post_id 
    FROM PostTags pt 
    JOIN tags t ON pt.tag_id = t.id 
    WHERE t.name = 'xyz') 

Une autre façon de faire est la suivante:

SELECT p.* 
FROM posts p 
JOIN posttags pt ON p.id = pt.post_id 
JOIN tags t ON pt.tag_id = t.id 
WHERE EXISTS 
    (SELECT post_id 
    FROM PostTags pt 
    JOIN tags t ON pt.tag_id = t.id 
    WHERE t.name = 'xyz' 
    AND pt.post_id = p.id) 

Les performances les plus performantes doivent être testées et peuvent varier en fonction du fournisseur et de la version de la base de données. Un bon optimiseur (c.-à-d. Oracle) les optimisera probablement pour effectuer la même chose. D'autres ne peuvent pas.

Maintenant, cela vous obtiendrez des lignes arrière comme ceci:

Post 1, tag 1 
Post 1, tag 2 
Post 3, tag 2 
Post 3, tag 3 

vous aurez donc besoin de les combiner, de préférence dans la logique applicative plutôt que SQL. Certains SGBDR ont des extensions spécifiques au fournisseur pour ce genre de choses, comme la fonction GROUP_CONCAT() de MySQL.

+0

je l'ai fait juste 'SELECT post, tags FROM Application \ Modèles \ Post poste INNER JOIN post.tags tags' b4 j'ai vu ce poste, et il semble fonctionner. sans le nom de l'étiquette tho. Y a-t-il une différence entre le tien et le mien? –

+0

Je trouve aussi qu'en raison de la clause where, seule la balise spécifiée ici est sélectionnée. Je veux recevoir des messages avec cette balise. mais pour les messages correspondants, je veux tout, pas seulement l'étiquette spécifiée. peut-être que je travaille sur une sous-requête –

+0

@jiewmeng Je ne comprends pas vos questions. – cletus

Questions connexes