代码之家  ›  专栏  ›  技术社区  ›  Max Cantor

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

  •  10
  • Max Cantor  · 技术社区  · 16 年前

    假设我有一个带有两列的“tags”表: 塔吉德 争辩 .每一行表示分配给一个内容块的标记。我想要一个查询,它将为我提供每一个标签为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个标记的交集怎么办?这很快就会变得可怕。有什么想法吗?

    编辑 :原来这也包括在 this excellent blog post .

    5 回复  |  直到 16 年前
        1
  •  24
  •   Amy B    16 年前
    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
    
        2
  •  2
  •   adrian    16 年前

    这里有一个解决方案,在一个非常大的对象和标记数据库中,它的工作速度比for me快得多。这是一个三标记交叉的例子。它只是在对象标记表上链接许多连接( objtags )指示同一对象并在 WHERE 条款:

    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(...) 解决方案。

        3
  •  1
  •   albertein    16 年前

    我能想到的唯一替代方法是:

    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
    
        4
  •  0
  •   Bob Probst    16 年前

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

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

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

        5
  •  -1
  •   Meff    16 年前

    什么类型的SQL?MS SQL Server、Oracle、MySQL?

    在SQL Server中,这不等于:

    select contentid from tags where tagid IN (334,338,342)