考虑三个表:一个项目,一个是这些项目上的标签,第三个是将标签ID映射到标签名称。
项目:
ITEM ID ITEM NAME
-------------------
1 Item 1
2 Item 2
3 Item 3
标签:
ID TAG ID ITEM ID
1 1 1
2 2 1
3 3 1
4 1 2
5 1 3
标记名称:
TAG ID TAG NAME
1 TAG_A
2 TAG B
3 TAG C
因此,只有第1项标签为TAG_A,TAG_B和TAG_C。
如何选择检索所有具有TAG_A,TAG_B和TAG_C的项目而不进行3次INNER JOIN?换句话说,我知道我可以做一个选择并说出
INNER JOIN item_tags pt4 ON pt4.item_id = p.item_id AND pt4.tag_id = 1
INNER JOIN item_tags pt13 ON pt13.item_id = p.item_id AND pt13.tag_id = 2
INNER JOIN item_tags pt19 ON pt19.item_id = p.item_id AND pt19.tag_id = 3
但那效率低下,对吧?
子查询怎么样,比如
SELECT * FROM items WHERE ... AND item_id IN(SELECT item_id
来自item_tags
WHERE tag_id
IN(1,2,3))
(这个确切的查询不起作用 - 它是标签上的OR,但这就是我想要的。)
答案 0 :(得分:2)
尝试此查询 -
SELECT t.item_id FROM tags t
JOIN tag_names tn
ON t.tag_id = tn.tag_id
GROUP BY
t.item_id
HAVING
COUNT(DISTINCT t.tag_id) = (SELECT COUNT(*) FROM tag_names)
答案 1 :(得分:0)
第一个查询(别名sqlvars)创建一个@NumTags变量,表示标记名称表中有多少个标记,因此不需要在每个符合条件的标记组上执行此操作。
第二个查询(别名HasAllTags)获取项目,按itemid分组,总计数等于@NumTags。
最后,HasAllTags与项目连接以提取数据。
select
I.*
from
( select @NumTags := (select count(*) from TagName )) sqlvars,
( select t.ItemID
from Tags t
group by t.ItemID
having count(*) = @NumTags ) HasAllTags
JOIN Items I
on HasAllTags.ItemID = I.ItemID