2010-04-06 1 views
0

Я создаю приложение для заметок для себя с функциями фильтрации тегов, но у меня проблема при попытке захватить заметки с помощью тегов. Фильтр тегов должен использовать AND, а не IN, потому что это поможет лучше сузить то, что я ищу.MySQL LEFT JOIN проблема с тремя операторами WHERE

Мои таблицы настроены так:

+ notes   note_id | note_title | note_uid 

+ tags   tag_id | tag_title 

+ notes_tags  nt_id | nt_note_id | nt_tag_id 

Таблица notes_tags отслеживает теги всех нот.

Я не беспокоится о возвращении информации о тегах, так вот пример LEFT JOIN Я использую в настоящее время, чтобы получить только ноты с только 1 тега.

SELECT * FROM notes_tags LEFT JOIN заметки на note_id = nt_note_id WHERE note_uid IN (1) И nt_tag_id = 10

Этот запрос работает идеально, он захватывает все ноты с этим один тег , Тем не менее, у меня возникли проблемы "Pinpointing" мои заметки, используя запрос, как это:

SELECT * FROM notes_tags LEFT JOIN заметки на note_id = nt_note_id WHERE note_uid IN (1) И nt_tag_id = 10 И nt_tag_id = 11

Что я делаю неправильно с синтаксисом?

+0

Вы пытаетесь получить заметки, которые находятся в обоих тегах 10 и 11, я принимаю это? Вы не можете сделать это только с И, взгляните на этот похожий вопрос со вчерашнего дня: http://stackoverflow.com/questions/2581067/mysql-experts-need-help-with-intersect/2581145#2581145 –

ответ

2

Предполагая, что вы хотите идентифицировать заметки, имеющие связанные записи notes_tags с nt_tag_ids 10 и nt_tag_ids из 11, тогда внешнее соединение просто заставляет СУБД работать сложнее, чем нужно.

Это кажется наиболее очевидное решение:

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); 

Альтернативный подход был бы:

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; 

Примечание это предполагает, что их это уникальное ограничение на nt_note_id и nt_tag_id в таблице notes_tags.

Но оба вышеизложенного возвращают данные только в таблице заметок. Если вам нужно извлечь соответствующие строки из таблицы разложения 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 

Вы можете добавить псевдонимы столбцов выходных данных, чтобы сделать анализ ответа немного проще.

+0

Спасибо! Это работает отлично. – hatfieldajoshua

2

nt_tag_id = 10 AND nt_tag_id = 11 это всегда возвращает ложное

использование nt_tag_id in (10,11) вместо

если вам нужны обе метки есть ответ ниже с присоединением таблицы тегов дважды

+0

, используя IN (10, 11) будет работать, если он хочет заметок, которые находятся в 10 * или * 11, но если он хочет, чтобы те, которые находятся в 10 * и * 11, зависят от того, к чему он стремится. –

+0

Надеюсь, я правильно понял, что одно поле не может равняться как 10, так и 11 одновременно – vittore

2

Это будет возвращать только ноты, которые имеют как tag_id 10 и 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

Вы используете «И» вместо этого используется «или» в пункте, где, как это:

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) 

Вы можете использовать IN также, как это, если вы собираетесь добавить больше 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)