【问题标题】:How to express this SQL query without subqueries如何在没有子查询的情况下表达这个 SQL 查询
【发布时间】:2020-08-09 15:26:19
【问题描述】:

我有一个包含project, keyphrase, article, and category 表的数据库。项目可以有多个关键词和多个类别,文章也可以。所以我对每个关系都有各自的连接表。

我有一个查询,可以找到与特定项目(即 26 篇)共享关键词和类别的所有文章。

SELECT DISTINCT article.id, article.summary
FROM article, articles_categories, articles_keyphrases 
WHERE id = articles_categories.article_id AND id = articles_keyphrases.article_id 
AND category_id IN (SELECT category_id FROM projects_categories WHERE project_id = 26)
AND keyphrase_id IN (SELECT keyphrase_id FROM projects_keyphrases WHERE project_id = 26)

我正在尝试寻找一种不同的方式来编写它,以便没有任何子查询。这主要只是我的一个学习练习,因为我真的很想看到这个查询的不同方法。

【问题讨论】:

  • 子查询是高效的
  • @Andronicus 我知道。这是一个学习练习。我并不希望一定要提高性能。
  • summary 列驻留在哪个表中?
  • @Andronicus idsummary 都来自 article
  • Travis 你试图做的是对数据库的过度杀伤(它不是正确使用连接)

标签: sql database postgresql subquery relational-database


【解决方案1】:

你可以JOIN所有四个表来获得相同的结果。请注意,逗号连接已被取代数十年,您应该改为编写 ANSI 连接:

SELECT DISTINCT id, summary
FROM article a
JOIN articles_categories ac ON ac.article_id = a.id
JOIN articles_keyphrases ak ON ak.article_id = a.id
JOIN projects_categories pc ON pc.category_id = ac.category_id AND pc.project_id = 26
JOIN projects_keyphrases pk ON pk.keyphrase_id = ak.keyphrase_id AND pk.project_id = 26

【讨论】:

  • 不错的解决方案,我没有注意到from 中的两个表与内部选择(+1)中的表不同。尽管有 2 个结果列并且没有瞬态关系,但所有这些连接都只是浪费资源,应该转换为 exists
  • @Andronicus 我同意存在 - 将其发布为答案,我很乐意报答。
【解决方案2】:

DISTINCT 是不需要的(而且总是一个危险信号,恕我直言)。

由于只选择了 a 表中的字段,因此您可以通过将所有不需要的表引用压缩到 exists() 子查询中来避免生成重复项(以及以后需要禁止它们):


SELECT id, summary
FROM article a
WHERE EXISTS (
        SELECT * FROM articles_categories ac 
        JOIN projects_categories pc
            ON pc.category_id = ac.category_id AND pc.project_id = 26
        WHERE ac.article_id = a.id
        )
AND EXISTS      (
        SELECT * FROM articles_keyphrases ak 
        JOIN projects_keyphrases pk
            ON pk.keyphrase_id = ak.keyphrase_id AND pk.project_id = 26
        WHERE ak.article_id = a.id
        )
        ;

【讨论】:

  • 我真的很喜欢这个解决方案,因为它将存在谓词完全与主查询分离!
【解决方案3】:

由于@Nick 已经发布了一个很好的答案,我将分享一些不能回答您的问题但效果最好的内容:

select distinct a.id, a.summary
from article a
join articles_categories ac on ac.article_id = a.id
join articles_keyphrases ak on ak.article_id = a.id
and exists (select * from projects_categories pc where pc.category_id = ac.category_id and pc.project_id = 26)
and exists (select * from projects_keyphrases pk where pk.keyphrase_id = ak.keyphrase_id and pk.project_id = 26)

【讨论】:

  • projects_categoriesprojects_keyphrases 都不包含 article_ids。
  • @TravisM 好吧,我误读了查询,并认为它与子查询中的内容交叉连接,已更正
  • 这更高效的原因是因为它只是检查条件,而不是加入所有内容?
  • @TravisM 这是否比 4 次连接更高效将在很大程度上取决于您的数据和表结构。 Google sql join vs exists performance 产生了很多有趣的阅读。
  • @TravisM postgres 检查子查询中是否存在,所以当只找到匹配项时,满足谓词并继续前进,它不必加入整个表来检查是否存在行存在,查看这篇文章:blog.jooq.org/2016/03/09/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
相关资源
最近更新 更多