Postgresql return 每条评论的回复数
Postgresql return number of replies for each comment
我有一条评论 table 看起来像:
CREATE TABLE comments (
comment_id INT GENERATED ALWAYS AS IDENTITY,
user_id VARCHAR(255) NOT NULL,
username VARCHAR(15) NOT NULL,
content VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
post_id VARCHAR(255) references posts(post_id),
reply_to INT,
);
对于每条评论,我都在尝试 select 回复的数量。作为回复的评论将有一个 reply_to
列引用 comment_id
回复也是回应。
我正在尝试 select 所有响应 post 的列,但是我还想 select 每个评论的回复数量。
这是查询:
SELECT comment_id, username, content,
(
SELECT COUNT(comments.*) FROM comments
JOIN comments comments1 on comments.comment_id = comments1.reply_to
)
as replies FROM comments WHERE post_id = 'uuid';
查询returns:
comment_id
username
content
replies
2
username1
comment content
1
3
username2
comment content
1
问题是 returns 两条评论的回复计数均为 1,即使我只有 1 条记录的 reply_to
列为 3。
为什么您的解决方案不起作用
您在 SELECT 子句中使用的子查询是在内部连接所有评论及其所有回复,然后对结果 table 中的所有结果行进行计数。请注意,您在示例中使用了内部联接(JOIN 是 shorthand 表示 INNER JOIN),因此如果评论没有任何回复,则它不会包含在结果 table 中。所以计数是所有至少有一个回复的评论。
(
-- you are counting ***ALL** the comments in your table inner joined onto their replies.
SELECT COUNT(comments.*) FROM comments
JOIN comments comments1 on comments.comment_id = comments1.reply_to
)
但是您希望将计数范围限定为每个评论,以便它只是他们回复的计数,而不是整个 table。
解决方法
假设回复只能深入一层,那么我相信您可以使用横向连接或使用 window 函数的常见 table 表达式。
这里是用横向连接解决它的方法。如果我以后有时间,我会用 window 函数方法更新我的答案。然而,我认为平均而言,横向连接比 window 函数方法更高效,尽管它可能取决于您的数据。
create temporary table comments (
id serial primary key,
post_id int,
reply_to_id int,
body varchar
);
-- the body for each comment illustrates the comment hierarchy for a post
-- POST.PARENT_COMMENT.REPLY. E.g. 1.1.1 means this comment is a reply to the first comment for the first post.
insert into comments (post_id, reply_to_id, body) values
(1, null, '1.1'),
(1, 1, '1.1.1'),
(1, 1, '1.1.2'),
(1, null, '1.2'),
(2, null, '2.1'),
(2, 5, '2.1.1');
-- Lets look at the comments with their replies
select comments.*, replies.* from comments
left outer join comments as replies on comments.id = replies.reply_to_id
order by comments.post_id, replies.reply_to_id ASC;
/*
| COMMENT | REPLY |
id | post_id | reply_to_id | body | id | post_id | reply_to_id | body
----+---------+-------------+-------+----+---------+-------------+-------
1 | 1 | | 1.1 | 3 | 1 | 1 | 1.1.2
1 | 1 | | 1.1 | 2 | 1 | 1 | 1.1.1
3 | 1 | 1 | 1.1.2 | | | |
2 | 1 | 1 | 1.1.1 | | | |
4 | 1 | | 1.2 | | | |
5 | 2 | | 2.1 | 6 | 2 | 5 | 2.1.1
6 | 2 | 5 | 2.1.1 | | | |
*/
--- now lets get the reply count
select comments.*, r.reply_count from comments
left join lateral (
select count(replies.id) as reply_count from comments as replies
where comments.id = replies.reply_to_id
) as r on true
order by comments.post_id ASC;
/*
id | post_id | reply_to_id | body | reply_count
----+---------+-------------+-------+-------------
1 | 1 | | 1.1 | 2
2 | 1 | 1 | 1.1.1 | 0
3 | 1 | 1 | 1.1.2 | 0
4 | 1 | | 1.2 | 0
5 | 2 | | 2.1 | 1
6 | 2 | 5 | 2.1.1 | 0
*/
我有一条评论 table 看起来像:
CREATE TABLE comments (
comment_id INT GENERATED ALWAYS AS IDENTITY,
user_id VARCHAR(255) NOT NULL,
username VARCHAR(15) NOT NULL,
content VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
post_id VARCHAR(255) references posts(post_id),
reply_to INT,
);
对于每条评论,我都在尝试 select 回复的数量。作为回复的评论将有一个 reply_to
列引用 comment_id
回复也是回应。
我正在尝试 select 所有响应 post 的列,但是我还想 select 每个评论的回复数量。
这是查询:
SELECT comment_id, username, content,
(
SELECT COUNT(comments.*) FROM comments
JOIN comments comments1 on comments.comment_id = comments1.reply_to
)
as replies FROM comments WHERE post_id = 'uuid';
查询returns:
comment_id | username | content | replies |
---|---|---|---|
2 | username1 | comment content | 1 |
3 | username2 | comment content | 1 |
问题是 returns 两条评论的回复计数均为 1,即使我只有 1 条记录的 reply_to
列为 3。
为什么您的解决方案不起作用
您在 SELECT 子句中使用的子查询是在内部连接所有评论及其所有回复,然后对结果 table 中的所有结果行进行计数。请注意,您在示例中使用了内部联接(JOIN 是 shorthand 表示 INNER JOIN),因此如果评论没有任何回复,则它不会包含在结果 table 中。所以计数是所有至少有一个回复的评论。
(
-- you are counting ***ALL** the comments in your table inner joined onto their replies.
SELECT COUNT(comments.*) FROM comments
JOIN comments comments1 on comments.comment_id = comments1.reply_to
)
但是您希望将计数范围限定为每个评论,以便它只是他们回复的计数,而不是整个 table。
解决方法
假设回复只能深入一层,那么我相信您可以使用横向连接或使用 window 函数的常见 table 表达式。
这里是用横向连接解决它的方法。如果我以后有时间,我会用 window 函数方法更新我的答案。然而,我认为平均而言,横向连接比 window 函数方法更高效,尽管它可能取决于您的数据。
create temporary table comments (
id serial primary key,
post_id int,
reply_to_id int,
body varchar
);
-- the body for each comment illustrates the comment hierarchy for a post
-- POST.PARENT_COMMENT.REPLY. E.g. 1.1.1 means this comment is a reply to the first comment for the first post.
insert into comments (post_id, reply_to_id, body) values
(1, null, '1.1'),
(1, 1, '1.1.1'),
(1, 1, '1.1.2'),
(1, null, '1.2'),
(2, null, '2.1'),
(2, 5, '2.1.1');
-- Lets look at the comments with their replies
select comments.*, replies.* from comments
left outer join comments as replies on comments.id = replies.reply_to_id
order by comments.post_id, replies.reply_to_id ASC;
/*
| COMMENT | REPLY |
id | post_id | reply_to_id | body | id | post_id | reply_to_id | body
----+---------+-------------+-------+----+---------+-------------+-------
1 | 1 | | 1.1 | 3 | 1 | 1 | 1.1.2
1 | 1 | | 1.1 | 2 | 1 | 1 | 1.1.1
3 | 1 | 1 | 1.1.2 | | | |
2 | 1 | 1 | 1.1.1 | | | |
4 | 1 | | 1.2 | | | |
5 | 2 | | 2.1 | 6 | 2 | 5 | 2.1.1
6 | 2 | 5 | 2.1.1 | | | |
*/
--- now lets get the reply count
select comments.*, r.reply_count from comments
left join lateral (
select count(replies.id) as reply_count from comments as replies
where comments.id = replies.reply_to_id
) as r on true
order by comments.post_id ASC;
/*
id | post_id | reply_to_id | body | reply_count
----+---------+-------------+-------+-------------
1 | 1 | | 1.1 | 2
2 | 1 | 1 | 1.1.1 | 0
3 | 1 | 1 | 1.1.2 | 0
4 | 1 | | 1.2 | 0
5 | 2 | | 2.1 | 1
6 | 2 | 5 | 2.1.1 | 0
*/