如何使用一个必需条件和一个可选条件来连接两个表

时间:2011-06-20 04:21:45

标签: mysql sql

我有一个media表和一个tag_media表。 tag_media表是包含列id_tagid_media的关系表。单个媒体文件可以使用多个标签进行标记。类似的东西:

tag_media:
    id_tag
    id_media

media:
    id_media
    (etc, etc)

我需要一个查询,这将允许我获取所有标记有一组强制标记和一组可选标记的媒体,以便我可以保证返回的媒体被标记为所有必需标记,并且至少标记一个可选标签。

我该怎么做?

4 个答案:

答案 0 :(得分:6)

此查询将执行您要查找的内容:

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

我更喜欢这样的结构,因为那时信息只列出一次:

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

如果您可以在MySQL中使用CTE,那么将S派生表转换为CTE(或将其放在临时表中)将允许您将<n>从所需的选项数字更改为{{1 }}

注意:从技术上讲,这些查询可以重写为完全针对tag_media表。但是如果你想从媒体表中提取其他信息,那么这就是你可能会这样做的。

答案 1 :(得分:3)

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 :(得分:2)

这也应该有效(基于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');

答案 3 :(得分:1)

为所有强制标记创建一个exists子句,并通过计数检查总数,并且对于所有非必需标记存在一个

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
)