使用一个嵌套级别计算注释

时间:2013-11-11 20:51:14

标签: sql postgresql count

我有一个评论系统,用户可以对帖子发表评论,然后用户可以回复这些顶级评论。这是嵌套的扩展:用户无法回复回复。

顶级评论和回复同时存在于同一个表格中。它们几乎相同。顶级评论的评论为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_id,对值进行非规范化。然后第一个查询将计算所有这些。如果我这样做,我真的希望在数据库中进行某种一致性检查,以确保我做对了。

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

或者,还有另一种好方法可以一举统计所有评论吗?

2 个答案:

答案 0 :(得分: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来说明没有回复的帖子。

答案 1 :(得分: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将此查询用作关联,这将是非常好的。)