#javascript #sql #node.js #postgresql #greatest-n-per-group
#javascript #sql #node.js #postgresql #наибольшее число на группу
Вопрос:
У меня есть 2 таблицы в моей базе данных postgresql. Упрощенно они выглядят так:
// table: articles
---- ----------- ---------------
| id | title | body |
---- ----------- ---------------
| 1 | hello | world |
| ... |
---- ----------- ---------------
// table: comments
---- ----------- ---------------
| id | articleid | comment |
---- ----------- ---------------
| 1 | 1 | looks cool! |
| ... |
---- ----------- ---------------
Я хочу создать обзорную страницу со всеми статьями последние 3 комментария к каждой статье. Возможно ли это с помощью одного запроса?
Мои запросы теперь выглядят так (NodeJS):
let query, values, resu<
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, или (если это невозможно), наиболее эффективный способ сделать это.
Пожалуйста, обратите внимание, что обе таблицы больше, чем упрощенные версии, которые я описал здесь. В настоящее время у меня 1700 статей и 100 000 комментариев.
Ответ №1:
Я считаю, что простой:
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 /
Комментарии:
1. Спасибо. Я посмотрю на это.
2. Здесь
rank()
,dense_rank()
иrow_number()
будут делать то же самое для вывода, ноrow_number()
будут лучше других по производительности
Ответ №2:
Один из вариантов использует боковое соединение:
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