Как объединить две таблицы с одним обязательным и необязательным условием - PullRequest
4 голосов
/ 20 июня 2011

У меня есть таблица media и таблица tag_media. Таблица tag_media - это таблица отношений, которая содержит столбцы id_tag и id_media. Один медиа-файл может быть помечен несколькими тегами. Что-то вроде:

tag_media:
    id_tag
    id_media

media:
    id_media
    (etc, etc)

Мне нужен запрос, который позволит мне выбрать все носители, которые были помечены набором обязательных тегов и набором необязательных тегов, чтобы я мог гарантировать, что возвращенный носитель был помечен ВСЕМИ обязательными тегами и по крайней мере один из необязательных тегов.

Как я могу это сделать?

Ответы [ 4 ]

6 голосов
/ 20 июня 2011

Этот запрос будет делать то, что вы ищете:

SELECT
   M.id_media
FROM
   media M
   INNER JOIN tag_media T ON M.id_media = T.id_media
WHERE T.id_tag IN ('required1', 'required2', ... 'optional1', 'optional2', ...)
GROUP BY M.id_media
HAVING
   Sum(T.id_tag IN ('required1', ... 'requiredn')) = <n>
      -- where n is the required number of tags
   AND Sum(T.id_tag IN ('optional1', ... 'optionaln')) >= 1

Я предпочитаю подобные конструкции, хотя, потому что тогда информация перечисляется только один раз:вы можете использовать CTE в MySQL, а затем преобразовать производную таблицу S в CTE (или поместить ее во временную таблицу) позволит вам изменить <n> с буквального числа необходимых параметров на (SELECT Count(*) from S).

Примечание: технически эти запросы можно переписать так, чтобы они полностью соответствовали таблице tag_media.Но если вы хотите извлечь другую информацию из таблицы мультимедиа, то именно так вы и сделаете.

3 голосов
/ 20 июня 2011
SELECT m.*
FROM media m
  INNER JOIN (
    SELECT id_media
    FROM tag_media
    GROUP BY id_media
    HAVING COUNT(id_tag IN (required1, required2) OR NULL) = 2
       AND COUNT(id_tag IN (option1, option2, option3) OR NULL) >= 1
  ) t ON m.id_media = t.id_media

Предполагается, что один элемент мультимедиа не может иметь дубликаты тегов.

2 голосов
/ 20 июня 2011

Это также должно работать (на основе ключевого слова ALL и IN):

SELECT `M`.`id_media`
FROM `media` `M`
INNER JOIN `tag_media` `TM` ON `M`.`id_media` = `TM`.`id_media`
WHERE `TM`.`id_tag` = ALL ('required_tag_1', 'required_tag_2', 'required_tag_3')
AND `TM`.`id_tag` IN ('optional_tag_1', 'optional_tag_2', 'optional_tag_3');
1 голос
/ 20 июня 2011

Создайте предложение о существовании для всех обязательных тегов и сверьтесь с итогом путем подсчета, и один существует для всех необязательных

SELECT id_media 
FROM media
WHERE EXISTS
(SELECT COUNT(*)
FROM tag_media
WHERE  tag_media.id_media IN (mandatory1, mandatory2, ...)
AND media.id = tag_media.media_id -- Comment: Used to join with the outer table
GROUP BY id_media
HAVING COUNT(*)>= n -- the required tag total
)
AND
EXISTS
(SELECT *
FROM tag_media
WHERE  tag_media.id_media IN (NotMandatory1, NotMandatory2, NotMandatory3)
AND media.id = tag_media.media_id
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...