Исключение строк с отношениями «многие ко многим» - PullRequest
3 голосов
/ 10 октября 2011

У меня есть три таблицы: posts, tags и posts_has_tags (которые облегчают отношения «многие ко многим» между записями и тегами).Сообщение может иметь любое количество тегов.

В таблице «posts» есть следующие столбцы: idposts text

В таблице «tags» есть следующие: idtags name

Что касается таблицы 'posts_has_tags': posts_idposts tags_idtags

Что я не могу сделать, так это предложить запрос для выбора всех сообщений, кроме тех, которые имеют тег (или теги) с определенным значением в назначенном им столбце «имя».Кажется, что он должен содержать «НЕ СУЩЕСТВУЕТ», но я не могу полностью обернуть его вокруг.

Спасибо за вашу помощь заранее.

РЕДАКТИРОВАТЬ:

Кроме того, возможно ли одновременно ограничить набор результатов определенными тегами?Например:

теги для исключения: a, b теги для включения: c

Запись с тегами 'a', 'f' не превращается в набор результатов (потому что нет, если этотеги включены).Запись с тегами 'a', 'b', 'c' также не входит в набор результатов (потому что это 'a' и 'b' - исключенные теги).Публикация с тегами 'c', 'f' превращает ее в набор результатов, потому что 'c' является включенным тегом.

FINAL EDIT Я наконец нашел решение, которое, кажется, работаети достаточно хорошо работает: http://www.mysqldiary.com/a-many-to-many-relationship-table-solving-the-exclude-relation-problem/

Ответы [ 4 ]

4 голосов
/ 10 октября 2011

Вы можете использовать анти-объединение.

SELECT p.* 
FROM posts p
LEFT JOIN post_has_tags pt ON (pt.post_id = p.id)
LEFT JOIN tags t ON (t.id = pt.tag_id AND t.name IN ('test','test1','test2'))
WHERE t.id IS NULL
GROUP BY p.id

Если вы хотите принудительно включить другие теги, вы делаете другое объединение.

SELECT p.* 
FROM posts p
LEFT JOIN post_has_tags pt ON (pt.post_id = p.id)
LEFT JOIN tags t ON (t.id = pt.tag_id AND t.name IN ('a','b'))
INNER JOIN tags t2 ON (t2.id <> t.id AND t2.id = pt.tag_id AND t2.name IN ('c')) 
WHERE t.id IS NULL
GROUP BY p.id

Это будет определять приоритет исключения надвключение.
Если вы хотите установить приоритетность включения, замените внутреннее соединение на:

INNER JOIN tags t2 ON (t2.id = pt.tag_id AND t2.name IN ('c')) 
3 голосов
/ 10 октября 2011
SELECT p.* 
FROM posts AS p
WHERE NOT EXISTS
      ( SELECT *
        FROM posts_has_tags AS pt
          JOIN tags AS t
            ON pt.tags_idtags = t.idtags
        WHERE pt.posts_idposts = p.idposts
          AND t.name = @CertainForbiddenTagName
      )

Если вам нужно запретить много имен тегов, используйте это вместо:

          AND t.name IN (List of ForbiddenTagNames)

Для вашего обновленного второго вопроса просто добавьте аналогичный EXISTS:

   AND EXISTS
       ( SELECT *
         ...
       )
0 голосов
/ 11 октября 2012

Я наконец нашел решение, которое, кажется, работает и достаточно эффективно: http://www.mysqldiary.com/a-many-to-many-relationship-table-solving-the-exclude-relation-problem/

0 голосов
/ 10 октября 2011
select * from posts where idposts in 
(select posts_has_tags.posts_idposts from posts_has_tags   
join tags on tags.idtags = posts_has_tags.tags_idtags  
 where tags.name not in ('value1','value2',...))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...