用一层嵌套计算评论

Posted

技术标签:

【中文标题】用一层嵌套计算评论【英文标题】:Counting comments with one level of nesting 【发布时间】:2013-11-11 20:51:14 【问题描述】:

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

*** cmets 和回复位于同一个表中。它们几乎完全相同。*** cmets 有一个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))))
);

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

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

告诉我#123 后有多少*** cmets。查询

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

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

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

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

或者,有没有其他好方法一举数出所有 cmets?

【问题讨论】:

我发布了未经测试的回复。如果您提供示例数据,我将创建SQL Fiddle,以便您进行测试。 这样的问题需要提供相关的表定义(就像你在psql中使用\d tbl一样。另外,你的Postgres版本。还有一些测试用例的示例数据会很好。 【参考方案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 来解释没有回复的帖子。

【讨论】:

【参考方案2】:

尤里卡! (感谢 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

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

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

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

【讨论】:

以上是关于用一层嵌套计算评论的主要内容,如果未能解决你的问题,请参考以下文章

easyui 子表格再嵌套一层表格,该怎样实现?

用 JQ 去除一层对象嵌套

以嵌套方式显示评论,如 Gmail 评论

嵌套对象的查询集排序

我如何在 angularjs 中显示子嵌套评论

如何实现嵌套评论系统?