2016-10-28 2 views
0

В большом проекте (сборник решенных проблем ...) У меня есть данные организованы следующим образом (типичный M: N отношение):поиск MySQL для записи, имеющие и не имеющие специфические теги

records | record_id, other_info 
tag_map | map_id, record_id, tag_id 
tags | tag_id, tag_text, other info 

I хотел бы добавить функцию фильтрации. В фильтре пользователь может выбрать для каждого тега, требуется ли его присутствие, проигнорировано или запрещено.

например. Мне нужно найти все записи, которые

  • имеет тег с tag_id = 1
  • И имеет тег с tag_id = 4
  • И не имеет тега с tag_id = 3
  • и любые другие теги не являются важный.
+0

'have tag with tag_id = 1 И иметь тег tag_id = 4' ... очевидно, это невозможно. Вы имели в виду OR? –

+0

Возможно - представьте себе книги и их теги: вымысел, приключение, документ, hasImages, wasFilmed. Теперь я хочу получить все книги, у которых есть изображения И были сняты И не вымысел. –

ответ

0

Если (record_id,tag_id) кортеж является уникальным в tag_map таблице, мы могли бы использовать комбинацию присоединиться и анти-операции соединения.

Например:

SELECT r.record_id 
    FROM records r 

    JOIN tag_map t1 
    ON t1.record_id = r.record_id 
    AND t1.tag_id = 1 

    JOIN tag_map t4 
    ON t4.record_id = r.record_id 
    AND t4.tag_id = 4 

    LEFT 
    JOIN tag_map t3 
    ON t3.record_id = r.record_id 
    AND t3.tag_id = 3 

    WHERE t3.record_id IS NULL 

Опять же, это основано на существовании единственности ограничения на (record_id,tag_id) в tag_map таблице. В противном случае у этого есть возможность вернуть «повторяющиеся» строки.

Есть другие шаблоны запросов, которые могут возвращать эквивалентные результаты. Например, мы можем использовать NOT EXISTS (correlated subquery) вместо антисоединения.

+0

Спасибо, это решение. –

0

SQL-запрос:

SELECT records.record_id, records.otherinfo FROM records, tags, tag_map 
WHERE records.record_id = tagmap.record_id AND tags.tag_id = tag_map.tag_id 
AND tags.tag_id = 1 AND tags.tag_id = 4 AND <> 3 
+0

Это все равно будет возвращать 'records', которые связаны с' tag_id' '3'. И он возвращает строки, связанные с 'tag_id' 1 или 4. Спецификация заключалась в том, что запись должна быть связана с * как * 1 и 4, так и не связана с 3. (Есть ли какая-то причина, по которой мы * все еще * используем старый синтаксис синтаксиса для совместной работы?) – spencer7593