2010-04-06 2 views
0

Je construis une application de prise de notes avec des fonctions de filtrage de balises, mais je rencontre un problème lorsque j'essaie de saisir des notes avec les balises. Le filtre de balise doit utiliser AND non IN, car il aidera à affiner ce que je cherche.Problème MySQL LEFT JOIN avec trois instructions WHERE

Mes tableaux sont configurés comme ceci:

+ notes   note_id | note_title | note_uid 

+ tags   tag_id | tag_title 

+ notes_tags  nt_id | nt_note_id | nt_tag_id 

La table notes_tags conserve la trace des balises de toutes les notes.

Je ne suis pas inquiet de retourner des informations sur les balises, alors voici un exemple LEFT JOIN J'utilise actuellement pour obtenir seulement des notes avec seulement 1 étiquette.

SELECT * FROM notes_tags LEFT JOIN Notes sur note_id = nt_note_id OÙ note_uid IN (1) ET nt_tag_id = 10

Cette requête fonctionne parfaitement, il saisit toutes les notes avec cette balise unique . Cependant, j'ai des problèmes "localisant" mes notes à l'aide d'une requête comme ceci:

SELECT * FROM notes_tags LEFT JOIN Notes sur note_id = nt_note_id OÙ note_uid IN (1) ET nt_tag_id = 10 ET nt_tag_id = 11

Qu'est-ce que je fais de mal avec la syntaxe?

+0

Vous essayez d'obtenir des notes qui se trouvent dans les étiquettes 10 et 11, je suppose? Vous ne pouvez pas le faire avec juste un ET, jetez un oeil à cette question similaire d'hier: http://stackoverflow.com/questions/2581067/mysql-experts-need-help-with-intersect/2581145#2581145 –

Répondre

2

En supposant que vous Si vous voulez identifier les notes qui ont des notes_tags associées avec nt_tag_ids 10 et nt_tag_ids de 11, alors la jointure externe ne fait que rendre le SGBD plus difficile que nécessaire.

Cela semble la solution la plus évidente:

SELECT * FROM notes n 
WHERE EXISTS (SELECT 1 FROM notes_tags nt 
    WHERE n.note_id=nt.nt_note_id 
    AND nt.nt_tag_id=10) 
AND EXISTS (SELECT 1 FROM notes_tags nt2 
    WHERE n.note_id=nt2.nt_note_id 
    AND nt2.nt_tag_id=11); 

Une autre approche serait:

SELECT n.*, COUNT(*) 
FROM notes n, 
notes_tags nt 
WHERE n.note_id-nt.nt_note_id 
AND nt.nt_tag_id IN (10,11) 
GROUP BY .... /* need to add these */ 
HAVING COUNT(*)=2; 

Notez cela suppose que leur est une contrainte unique sur nt_note_id et nt_tag_id dans la table notes_tags.

Mais les deux ci-dessus ne retourneront que les données dans le tableau des notes. Si vous avez besoin d'extraire les lignes correspondantes de la table de décomposition MN:

SELECT * 
FROM notes n, 
notes_tags nt, 
notes_tags nt2 
WHERE n.note_id=nt.nt_note_id 
AND n.note_id=nt2.note_id 
AND nt.nt_note_id=nt2.nt_note_id /* can help the optimizer come up with a faster query */ 
AND nt.nt_tag_id=10 
AND nt2.nt_tag_id=11 

Vous pouvez ajouter des alias aux colonnes de sortie pour faire l'analyse de la réponse un peu plus facile.

+0

Merci! Cela fonctionne parfaitement. – hatfieldajoshua

2

nt_tag_id = 10 AND nt_tag_id = 11 ce sera toujours return false

utilisation nt_tag_id in (10,11) au lieu

si vous avez besoin des deux balises il y a réponse ci-dessous avec se joindre à la table tag deux fois

+0

en utilisant IN (10, 11) fonctionnera s'il veut des notes en 10 * ou * 11, mais pas s'il en veut 10 * et * 11, cela dépend de ce qu'il vise. –

+0

J'espère que j'avais raison de deviner qu'un seul champ ne peut pas égaler à la fois 10 et 11 simultanément – vittore

2

Cela renverra uniquement les notes qui ont à la fois tag_id 10 et 11.

SELECT notes.* 
FROM notes 
INNER JOIN notes_tags a ON notes.note_id = a.nt_note_id 
         AND a.nt_tag_id = 10 
INNER JOIN notes_tags b ON notes.note_id = b.nt_note_id 
         AND b.nt_tag_id = 11 
0

Vous utilisez « ET » au lieu de cette utilisation « OU » dans la clause where comme ceci:

SELECT * FROM notes_tags LEFT JOIN notes ON note_id = nt_note_id WHERE note_uid IN (1) AND (nt_tag_id = 10 OR nt_tag_id = 11) 

vous pouvez utiliser aussi comme si vous allez ajouter plus nt_tag_id.

SELECT * FROM notes_tags LEFT JOIN notes ON note_id = nt_note_id WHERE note_uid IN (1) AND nt_tag_id IN (10, 11)