假设我有一个包含两列的“标签”表: tagid 和 contentid 。每行代表分配给一段内容的标签。我想要一个查询,它会给我一些标记为tagids 334,338和342的内容。
执行此操作的“简单”方法是(伪代码):
select contentid from tags where tagid = 334 and contentid in (
select contentid from tags where tagid = 338 and contentid in (
select contentid from tags where tagid = 342
)
)
然而,我的直觉告诉我,有更好,更快,更可扩展的方法来做到这一点。例如,如果我需要找到12个标签的交集怎么办?这很快就会变得可怕。有什么想法吗?
编辑:原来this excellent blog post也涵盖了这一点。
答案 0 :(得分:24)
SELECT contentID
FROM tags
WHERE tagID in (334, 338, 342)
GROUP BY contentID
HAVING COUNT(DISTINCT tagID) = 3
--In general
SELECT contentID
FROM tags
WHERE tagID in (...) --taglist
GROUP BY contentID
HAVING COUNT(DISTINCT tagID) = ... --tagcount
答案 1 :(得分:2)
这是一个在非常大的对象和标签数据库上比我更快的解决方案。这是三标签交叉的示例。它只链接对象标记表(objtags
)上的许多连接以指示相同的对象,并在WHERE
子句中规定标记ID:
SELECT w0.objid
FROM objtags t0
INNER JOIN objtags t1 ON t1.objid=t0.objid
INNER JOIN objtags t2 ON t2.objid=t1.objid
WHERE t0.tagid=512
AND t1.tagid=256
AND t2.tagid=128
我不知道为什么这会跑得更快。它的灵感来自MusicBrainz服务器中的搜索代码。在Postgres中这样做,我通常比HAVING COUNT(...)
解决方案快8到10倍。
答案 2 :(得分:1)
我能想到的唯一替代方法是:
select a.contentid from tags a
inner join tags b on a.contentid = b.contentid and b.tagid=334
inner join tags c on a.contentid = c.contentid and c.tagid=342
where a.tagid=338
答案 3 :(得分:0)
我不知道这是否更好但可能更易于维护
select contentid from tags where tagid = 334
intersect
select contentid from tags where tagid = 338
intersect
select contentid from tags where tagid = 342
您必须动态构建它,这不会像原始解决方案那样糟糕。
答案 4 :(得分:-1)
什么类型的SQL? MS SQL Server,Oracle,MySQL?
在SQL Server中,这不等于:
select contentid from tags where tagid IN (334,338,342)