MySQL LEFT JOIN проблема с тремя операторами WHERE - PullRequest
0 голосов
/ 07 апреля 2010

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

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

+ 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 tag.

SELECT * FROM notes_tags LEFT ПРИСОЕДИНЯЕТСЯ к заметкам ON note_id = nt_note_id ГДЕ note_uid IN (1) И nt_tag_id = 10

Этот запрос выполняется отлично, онзахватывает все заметки с этим одиночным тегом .Тем не менее, у меня возникают проблемы с «точным определением» моих заметок с помощью запроса, подобного следующему:

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

Что я не так делаю с синтаксисом?

Ответы [ 4 ]

2 голосов
/ 07 апреля 2010

Это вернет только ноты, которые имеют оба 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
2 голосов
/ 07 апреля 2010

Если вы хотите идентифицировать заметки, которые имеют связанные записи 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

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

2 голосов
/ 07 апреля 2010

nt_tag_id = 10 AND nt_tag_id = 11 это всегда будет возвращать false

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

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

0 голосов
/ 07 апреля 2010

Вы используете «И» вместо того, чтобы использовать «ИЛИ» в предложении where, например:

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