【问题标题】:Selecting primary from a mapping row SQL从映射行 SQL 中选择主要
【发布时间】:2012-03-28 10:18:13
【问题描述】:

我有一个引用一堆文章的表,该表包含这些文章的标签。像这样:

tag text
article_id bigint

我想选择所有带有一组标签的article_id,比如tag1、tag2、tag3,但文章也可以附加tag4、tag5。

我知道这会奏效:

SELECT article_id 
FROM tag WHERE tag='tag1' 
INTERSECT 
SELECT article_id 
FROM tag 
WHERE tag='tag2' 
INTERSECT 
SELECT article_id 
FROM tag 
WHERE tag='tag3'

这也是这样:

SELECT article_id 
FROM tag 
WHERE tag IN ('tag1','tag2','tag3') 
GROUP BY article_id 
HAVING count(*) = 3

但我不确定这是最有效的方法。我也一直在玩下面的,但目前无法让它工作。

SELECT array_agg(tag) as arr,
       article_id 
FROM tag 
GROUP BY article_id 
HAVING arr = {tag1,tag2,tag3}

这似乎是其他人会遇到的常见问题,我想知道在这种情况下,INTERSECT 是否是最有效的查询。它适用于 PostgreSQL。

【问题讨论】:

  • 如果您想找到最有效的查询,只需运行EXPLAIN ANALZYE

标签: sql postgresql sql-match-all relational-division


【解决方案1】:

我假设您需要来自article 的更多列,而不仅仅是article_id。不过,查询样式并没有太大变化。

您正在处理的称为关系划分。正如under this related question 所见,有很多方法可以给这只猫剥皮——包括关于索引和性能测试的建议。

我个人最喜欢的(而且很可能是最快的)是:

SELECT a.*
FROM   article a
JOIN   tag x USING (article_id)
JOIN   tag y USING (article_id)
JOIN   tag z USING (article_id)
WHERE  x.tag = 'tag1'
AND    y.tag = 'tag1'
AND    z.tag = 'tag3';

或者:

SELECT a.*
FROM   article a
WHERE  EXISTS (
   SELECT *
   FROM   tag x
   JOIN   tag y USING (article_id)
   JOIN   tag z USING (article_id)
   WHERE  x.article_id = a.article_id
   AND    x.tag = 'tag1'
   AND    y.tag = 'tag2'
   AND    z.tag = 'tag3'
   );

@David 已经解释了为什么您的第三个版本无法运行。但是无论如何你都不应该使用它,因为它不能使用索引,并且会比任何其他方法都慢一个数量级here

【讨论】:

    【解决方案2】:

    我个人喜欢第二种选择。但是您应该使用 PostgreSQL 的工具以及一些测试查询,看看哪个是最有效的。

    第三个不能像所写的那样工作的原因是你需要为 array_agg() 指定一个排序顺序: how to make array_agg() work like group_concat() from mySQL

    【讨论】:

    • 当重写它有点像“ SELECT article_id FROM tag GROUP BY article_id HAVING array_agg(tag::text ORDER BY tag)=ARRAY['tag1','tag2','tag3'];”但如果文章有 tag4 则它不会找到它。有没有一种方法可以基本上确保所有项目都在数组中,但数组不完全匹配?
    【解决方案3】:

    在您的最后一个变体中,您对数组相等性不感兴趣。您对数组包含感兴趣,HAVING arr 包含所有三个标签。

    而array1包含array2是PostgreSQL中的array1 @> array2

    我仍然希望 Erwin 的答案能够在性能方面赢得索引,这要归功于索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 2011-11-22
      • 1970-01-01
      相关资源
      最近更新 更多