在一个查询中为每篇文章选择文章 + 多条评论

Posted

技术标签:

【中文标题】在一个查询中为每篇文章选择文章 + 多条评论【英文标题】:select articles + multiple comments for each article in one query 【发布时间】:2020-12-20 11:50:17 【问题描述】:

我的 postgresql 数据库中有 2 个表。简化后,它们看起来像这样:

// table: articles
+----+-----------+---------------+
| id | title     | body          |
+----+-----------+---------------+
| 1  | hello     | world         |
| ...                            |
+----+-----------+---------------+

// table: comments
+----+-----------+---------------+
| id | articleid | comment       |
+----+-----------+---------------+
| 1  | 1         | looks cool!   |
| ...                            |
+----+-----------+---------------+

我想制作一个包含所有文章的概览页面 + 每篇文章的最后 3 个 cmets。这可以通过一个查询来实现吗?

我的查询现在看起来像这样(nodeJS):

let query, values, result;

let ret = [];

// query to select all articles, ordered by ID desc
query = 'SELECT id, title FROM articles ORDER BY id DESC';
result = await postgresql.query(query, []);

// store all rows in a constant
const articles = result.rows;

// loop over each article
articles.forEach(article => 
  // fetch the last 3 comments for each article
  query = 'SELECT id, comment FROM comments WHERE articleid = $1 ORDER BY id DESC LIMIT 3';
  values = [article.id];
  result = await postgresql.query(query, values);

  // store the comments in a constant
  const comments = result.rows;

  // push the article information (ID + title) and the comments in the ret array
  ret.push(
    articleID: article.id,
    title: article.title,
    comments: comments
  );
);

// ret now contains an array of objects of articles + comments
return ret;

我想知道是否可以将两个查询合并为 1,(如果不可能),这是执行此操作的最佳性能方式。

请注意,这两个表都比我在此处描述的简化版本要大。目前我有 + 1,700 篇文章和 +100,000 个 cmets。

【问题讨论】:

【参考方案1】:

一个选项使用横向连接:

select a.id, a.title, c.id, c.comment
from articles a
cross join lateral (
    select c.*
    from comments c
    where c.articleid = a.id
    order by id desc
    limit 3
) c
order by a.id desc, c.id desc

【讨论】:

【参考方案2】:

我相信,一个简单的:

select id, comment from 
(select a.id, c.comment, dense_rank() over PARTITION BY a.id ORDER BY c.id DESC) as rn from articles a join comments c on a.id = c.article_id) t
where t.rn <= 3;

所以是的,你只需要使用“DENSE_RANK()”函数https://www.postgresqltutorial.com/postgresql-dense_rank-function/

【讨论】:

谢谢。我去看看。 这里rank()dense_rank()row_number() 将在输出方面做同样的事情,但row_number() 在性能方面会比其他人更好

以上是关于在一个查询中为每篇文章选择文章 + 多条评论的主要内容,如果未能解决你的问题,请参考以下文章

在单个查询中为每个 DISTINCT 选择几条记录

在 CakePHP 3 中为文章添加评论

Gatsby 警告构建“查询时间过长”

如何编写在 Mysql 触发器中获取多条记录的选择查询?

《C#零基础入门之百识百例》(十三)选择结构 switch语句 -- 成绩查询

SQL DB2 条件选择