用于评论和评论回复的mysql结构

时间:2009-08-11 14:53:20

标签: mysql join

我一直在考虑这个问题很长一段时间了,我需要一种方法来添加对数据库中评论的回复,但我不确定如何继续。

这是我目前的评论表(并没有多说但是它的开头):

CREATE TABLE IF NOT EXISTS `comments` (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `comment` text,
  `user_id` int(12) DEFAULT NULL,
  `topic_id` int(12) NOT NULL,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;

这是我当前的查询:

SELECT c.id, c.comment, c.user_id, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
WHERE c.topic_id = 9

一个选项是创建一个名为“comment_replies”的新表,但我不确定如果我能够在一个查询中选择所有注释和注释回复,并且如果我添加一个名为“reply”的新列我不确定如何对每个回复进行排序以获得每条评论。

我希望得到一些关于如何处理这个问题的建议。

修改

根据以下答案,关于在1条评论和2条回复中添加parent_comment_id结果这类数据:

array(2) {
  [0]=>
  object(stdClass)#17 (7) {
    ["id"]=>
    string(2) "26"
    ["comment"]=>
    string(36) "adding a comment from the admin page"
    ["user_id"]=>
    string(2) "16"
    ["ts"]=>
    string(10) "1249869350"
    ["username"]=>
    string(5) "Admin"
    ["photo"]=>
    string(13) "gravatar2.png"
    ["reply"]=>
    string(23) "There is no admin page!"
  }
  [1]=>
  object(stdClass)#18 (7) {
    ["id"]=>
    string(2) "26"
    ["comment"]=>
    string(36) "adding a comment from the admin page"
    ["user_id"]=>
    string(2) "16"
    ["ts"]=>
    string(10) "1249869350"
    ["username"]=>
    string(5) "Admin"
    ["photo"]=>
    string(13) "gravatar2.png"
    ["reply"]=>
    string(13) "Yes there is!"
  }
}

如何处理此数组以使用它,是否可以将评论与回复分开?

7 个答案:

答案 0 :(得分:5)

如果您希望人们能够回复回复(例如,您可以在在线消息论坛中看到回复的层次结构),那么我会在评论表中添加一个可选的parent_comment_id字段。

你的桌子看起来像这样

`CREATE TABLE IF NOT EXISTS `comments` (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `parent_comment_id` int(12) NULL,
  `comment` text,
  `user_id` int(12) DEFAULT NULL,
  `topic_id` int(12) NOT NULL,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;`

显示所有评论和回复的查询类似于:

SELECT c.id, c.comment, r.comment as reply, c.user_id, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
LEFT JOIN comments r ON c.id = r.parent_comment_id
WHERE c.topic_id = 9

但请注意,对于此查询,您的回复不仅会显示在“回复”列中,还会显示在“评论”列中,作为额外的行,每个行都有零个或多个回复。

要显示回复评论的用户的用户名,您需要两次加入users表(首先是发布原始评论的用户,再次是回复的用户)。尝试此查询以显示回复的用户的用户名:

SELECT c.id, c.comment, c.user_id, u.username, u.photo, r.comment as reply, r.user_id as reply_user_id, 
u2.username as reply_username, u2.photo as reply_photo
FROM (comment c)
JOIN users u ON c.user_id = u.id
LEFT JOIN comments r ON c.id = r.parent_comment_id
JOIN users u2 ON r.user_id = u2.id
WHERE c.topic_id = 9

答案 1 :(得分:3)

在评论表中添加parent_comment_id列。让它可选。查询时,您可以将所有子注释加入到每个父项。作为一些选择性非规范化(轻微冗余),您可以确保在子注释上设置topic_id,让您更轻松地将它们拉出来(假设您要在主要注释中显示所有子注释)评论线程而不是通过较小的ajax请求。)

根据需要构建演示文稿,将结果投入memcached(或平面文件或内存......但是你正在缓存)并且你已经设置好了。

答案 2 :(得分:3)

我决定在数据库中添加parent_id列,而不是左边加入回复我刚刚选择了所有注释以便稍后用服务器端代码对注释和回复进行排序,继承查询:

SELECT c.*, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
WHERE c.topic_id = 9
ORDER BY c.id ASC

现在我将查询结果传递给下面的函数,以便每个回复都将作为数组添加到注释数组中,所以基本上它会返回一个多维数组。

function sort_comments($ar)
{
    $comments = array();
    foreach($ar as $item)
    {
        if(is_null($item['parent_id'])) $comments[] = $item;
        else 
        {
            $parent_array = array_search_key($item['parent_id'],$comments,'id');
            if($parent_array !== false) $comments[$parent_array]['replies'][] = $item;
        }
    }
    return $comments;
}

答案 3 :(得分:1)

评论回复是父评论_id的评论。尝试将comment_id作为字段添加到评论表中。你将得到的是树状结构。

如果您想要检索整个评论树,最好的办法是使用嵌套集(https://wiki.htc.lan/Hierarchy_model)。但这是一个更复杂的解决方案。

以下是来自MySQL的更多信息:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

答案 4 :(得分:1)

看起来您正在使用WordPress,添加parent_comment_id本来是一个理想的解决方案,但在这种情况下不会。

首先,我认为修改WordPress基本表不是一个好主意。其次,你最终会得到一个复杂的代码,它会破坏wordpress更新。

最好使用像Intense Comments

这样的插件

如果你想创建自己的解决方案,我会说创建另一个表来评论回复。 a)你的新表看起来像这样

`CREATE TABLE IF NOT EXISTS `comment_replies` (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `parent_comment_id` int(12) NULL,
  `comment` text,
  `user_id` int(12) DEFAULT NULL,
  `topic_id` int(12) NOT NULL,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8

b)你以这种方式获取它们

$comment_ids = array_map( 'intval', array_keys( $comments ) );
sort( $comment_ids );
$comments_id_list = join( ',', $comment_ids );

$query = "SELECT c.id, c.comment, c.user_id, u.username, u.photo
FROM (comment_replies c)
JOIN users u ON c.user_id = u.id
WHERE c.parent_comment_id IN ( $comments_id_list )"

$replies = $wpdb->get_results($query);
$replies_by_parent = array();

foreach ( array_keys( $replies ) as $i ) {          
    $replies_by_parent [$replies[$i]->id] = array();
}
foreach ( array_keys( $replies ) as $i ) {          
    $replies_by_parent [$replies[$i]->id][] =& $replies[$i];
}

c)现在,在您的评论循环中,您可以获得这样的回复

foreach (  $replies_by_parent [$parent_id] as $reply ) {            
        echo $reply->comment;
    }

答案 5 :(得分:1)

这似乎一切都很好但是如果表包含超过一百万行呢?并且一些评论可能相隔数十万行。这些查询将如何执行?

答案 6 :(得分:0)

function sort_comments($ar)
{
    $comments = [];
    $i=0;
    foreach($ar as $co){
      if(!empty($co['comment_replyof'])) {
        $comments[$co['comment_replyof']]['replies'] = $co;
      }else{
        foreach($co as $c => $o) $comments[$co['comment_id']][$c] = $o;
      }
    $i++;
    }
    return $comments;
}

SELECT C.*, U.id,U.fname, U.lname FROM (comment C) JOIN users U ON `enter code here`C.comment_user = U.id where C.comment_content='10'