我有一个media
表和一个tag_media
表。 tag_media
表是包含列id_tag
和id_media
的关系表。单个媒体文件可以使用多个标签进行标记。类似的东西:
tag_media:
id_tag
id_media
media:
id_media
(etc, etc)
我需要一个查询,这将允许我获取所有标记有一组强制标记和一组可选标记的媒体,以便我可以保证返回的媒体被标记为所有必需标记,并且至少标记一个可选标签。
我该怎么做?
答案 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
)