10

假设我有一个包含两列的“标签”表:tagidcontentid。每行代表分配给一段内容的标签。我想要一个查询,它会给我每条用 tagid 334、338 和 342 标记的内容的 contentid。

执行此操作的“简单”方法是(伪代码):

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 个标签的交集怎么办?这很快就会变得可怕。有任何想法吗?

编辑:原来这也包含在这篇优秀的博客文章中。

4

5 回答 5

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
于 2008-10-02T18:41:17.440 回答
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 中执行此操作,我通常会比解决方案获得约 8-10 倍的加速HAVING COUNT(...)

于 2008-11-20T04:17:36.273 回答
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
于 2008-10-02T18:40:35.103 回答
0

我不知道这是否更好,但它可能更易于维护

select contentid from tags where tagid = 334
intersect
select contentid from tags where tagid = 338
intersect
select contentid from tags where tagid = 342

您必须动态构建它,这不会像您原来的解决方案那样糟糕。

于 2008-10-02T18:45:02.033 回答
-1

什么类型的 SQL?MS SQL Server、甲骨文、MySQL?

在 SQL Server 中,这不等于:

select contentid from tags where tagid IN (334,338,342)
于 2008-10-02T18:42:02.043 回答