SQL查询:在多行上模拟“AND”而不是子查询

时间:2008-10-02 18:37:00

标签: sql join

假设我有一个包含两列的“标签”表: 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也涵盖了这一点。

5 个答案:

答案 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)