0

我有一个评论系统,用户可以在其中评论帖子,然后用户可以回复那些顶级评论。这就是嵌套的扩展:用户不能回复回复。

顶级评论和回复位于同一个表中。它们几乎完全相同。顶级评论有一个post_id,回复有一个parent_id。我在表上使用了一个约束来确保这些列中的一列对每一行都有一个值。

CREATE TABLE comments (
    id integer NOT NULL,
    post_id integer,
    author_id integer NOT NULL,
    body text,
    created_at timestamp without time zone,
    updated_at timestamp without time zone,
    parent_id integer,
    CONSTRAINT must_have_media_item_xor_parent CHECK ((((media_item_id IS NULL) AND (parent_id IS NOT NULL)) OR ((media_item_id IS NOT NULL) AND (parent_id IS NULL))))
);

现在我想统计特定帖子上的所有评论,包括回复。查询

SELECT count(*)
 FROM comments
WHERE comments.post_id = 123

告诉我#123 帖子有多少顶级评论。查询

SELECT count(*)
 FROM comments
 JOIN comments AS replies ON replies.parent_id = comments.id
WHERE comments.post_id = 123

告诉我有多少回复。我可以两者都做并将它们加在一起,但这听起来很重,希望没有必要。

一种避免来自第二个查询的自连接的解决方案是也设置post_idon 回复,使值非规范化。然后第一个查询将计算所有这些。如果我这样做,我真的很想在数据库中进行某种一致性检查,以确保我做对了。

有没有办法让 Postgres 在设置post_id时将其值限制为其父级的值parent_id?正常约束似乎只能查看单行。

或者,是否有另一种好方法可以一口气统计所有评论?

4

2 回答 2

1

好像PostgreSQL支持COUNT DISTINCT

您可能想尝试这样的事情:

SELECT (COUNT(comments.post_id) + COUNT(DISTINCT replies.post_id)) As Total_Count 
FROM comments
LEFT JOIN comments AS replies ON replies.parent_id = comments.id
WHERE comments.post_id = 123

我曾经LEFT JOIN考虑过没有回复的帖子。

于 2013-11-11T21:33:13.037 回答
1

尤里卡!(归功于 PM 77-1 从他的回答中获得灵感。)

我正在考虑向后加入。我需要从树叶中走回来,而不是从根部下来。

SELECT COUNT(*)
FROM comments
LEFT JOIN comments AS parents ON comments.parent_id = parents.id
WHERE comments.post_id = 123 OR parents.post_id = 123

翻译:获取所有评论,包括顶级评论和回复。如需回复,请获取有关其父母的信息。现在将该结果过滤到直接在该帖子上的评论回复该帖子上的父母的评论。

请注意,在我最初的问题尝试中,我的查询实际上并没有利用顶级评论和回复在同一个表中的事实。这个可以。它选择连接同一侧(左侧)的顶级评论和回复,并仅使用连接的右侧来获取更多信息以过滤回复。

(这也意味着我可以让 ActiveRecord 将此查询用作关联,这将是很不错的。)

于 2013-11-12T15:44:08.293 回答