对具有父子关系的评论进行分层查询?

时间:2018-04-09 21:56:17

标签: php mysql sql ajax recursive-query

我有一个使用adjacency list来存储分层数据的评论系统(我相信),例如:MySql表包含idparent_iddate列,...,没有parent_id的评论是主要评论,而parent_id的评论自然是回复。

在初始页面加载时,我进行Ajax调用,加载所有注释,而不是parent_id,所以所有主要注释。

SELECT * FROM comms WHERE parent_id IS NULL

现在,如果任何评论都回复了一个按钮,例如"加载回复"对于该注释显示,并且单击另一个调用,加载所有注释为parent_id的注释id的注释,然后递归查询加载回复的回复,依此类推。这很有效,问题在于,根据它们的加载顺序,您无法确定什么是重放。

所以我想要的是订购它们,以便重播在它所属的评论之下。

现在这只能从sql做ORDER BY id = parent_id这样的事情,对它们进行排序以使它们有些有意义或者我应该从php处理这个吗?或者我应该重新开始并以不同的方式存储它们?

编辑:第二个查询的一部分(取自this回答的例子,我发现了一段时间)

SELECT date_p, parent_id, id
   FROM (SELECT * FROM comms) rec,
   (SELECT @pv := 14) initialisation
   WHERE find_in_set(parent_id, @pv) > 0 
   AND @pv := concat(@pv, ',', id) ORDER BY ?

如果我愿意使用"替代品1"在我喜欢的答案中提供,订购的方法会不同或更好吗?

这就是我想要实现的目标:

<p>Main comm 1</p>
  <p>reply to main comm 1</p>
  <p>another reply to main comm 1</p>
    <p> replay to reply of main comm 1</p>
  <p> yet another reply to main comm 1</p>
<p>Main comm 2</p>
<p>Main comm 3</p>

3 个答案:

答案 0 :(得分:2)

由于这需要递归,并且MySQL pre v8并不能真正支持它,我倾向于解决PHP中的问题,它擅长递归。基本程序非常简单:

function show_children($db, $parent) {
    $sql = "SELECT * FROM comms WHERE parent_id " . ($parent ? "= $parent" : "IS NULL") . " ORDER BY date_p ASC";
    $result = $db->query($sql);
    if (!$result) return;
    while ($row = $result->fetch_assoc()) {
        echo "<p>" . $row['cmt'] . "</p>";
        show_children($db, $row['id']);
    }
}

show_children($db, 0);

从调用带有parent_id为0的show_children开始将获取所有顶级注释(带有parent_id = NULL的注释),递归将按日期顺序显示所有回复,但也按其父项的顺序显示(无论是评论还是回复)。

您还可以添加&#34;级别&#34;允许样式化输出的参数:

function show_children($db, $parent, $level = 0) {
    $sql = "SELECT * FROM comms WHERE parent_id " . ($parent ? "= $parent" : "IS NULL") . " ORDER BY date_p ASC";
    $result = $db->query($sql);
    if (!$result) return;
    while ($row = $result->fetch_assoc()) {
        echo "<p class=\"level$level\">" . $row['cmt'] . "</p>";
        show_children($db, $row['id'], $level+1);
    }
}

show_children($db, 0);

注意我已将mysqli视为数据库接口。

使用此例程,使用此输入数据:

id  date_p      parent_id   cmt
1   2018-03-21  (null)      Main comm1
2   2018-03-22  (null)      Main comm2
3   2018-03-22  1           reply to main comm 1
4   2018-03-23  1           another reply to main comm 1
5   2018-03-23  1           yet another reply to main comm 1
6   2018-03-24  4           replay to reply of main comm 1
7   2018-03-24  (null)      Main comm3

你会得到这个输出:

<p class="level0">Main comm1</p>
<p class="level1">reply to main comm 1</p>
<p class="level1">another reply to main comm 1</p>
<p class="level2"> replay to reply of main comm 1</p>
<p class="level1"> yet another reply to main comm 1</p>
<p class="level0">Main comm2</p>
<p class="level0">Main comm3</p>

答案 1 :(得分:-1)

很好的问题:

你现在拥有的是一个好主意:

我会将它存储在3个不同的表中,

tb1)主要评论 tb2)回复主评论 tb3)回复主评论的回复。

tb1包含像id(auto_increment)这样的列成为您的主要评论ID

tb2)包含id(auto_increment),main_comment_id,reply_to_main_comment_id

等列

tb3)有id(auto_increment),main_comment_id,reply_to_main_comment_id,reply_reply_id

<p1>main_comment_id</p1>
  <p2>reply_to_main_comment_id</p2>
     <p3>reply_reply_id</p3>

logically like the following:

    if(p1){
       post to tb1
    }elseif(p2){
       post to tb2
    }elseif(p3){
       post to tb3
    }


To get the comments for p1, (Select comments from tb1)
To get comments for p2, (Select comments from tb2 where main_comment_id=$id)
To get comments for p3, (Select comments from tb3 where main_comment_id=$id 
 and reply_to_main_comment_id=$id2)

$sql ("SELECT comments from tb3 WHERE main_comment_id=$id1 AND reply_to_main_comment_id=$id2 ORDER BY date DESC");

当你打电话给你的评论时,当然,你会按时间顺序显示它们,最新到最旧,你的p2成为p3的主要评论..它只是一个父母和一个孩子,但是你把它显示在一个扩展关系方式......这将是正确的评论....

希望这有效。我没有对此进行测试,但我开发了一个类似原理的数据库....

代码示例获得主要评论:

$comment1 = $_POST['comment1'];
$comment1_sql = ("Insert INTO tb1 (main_comment) VALUES ($comment1)");
$comment_result = mysqli_query($conn, $comment_sql1);

代码示例回复主要评论:

$comment2 = $_POST['comment2'];
$comment2_sql = ("Insert INTO tb2 (reply_to_main_comment) VALUES ($comment2)");
$comment_result = mysqli_query($conn, $comment_sql2);

与评论相同,回复主要评论的回复

答案 2 :(得分:-1)

我在MSSQL上工作,我非常确定CROSS APPLY会帮助你。我假设MYSQL确实有加入。

例如

SELECT A.PARENT_ID,A.COMMENT,* FROM T A 
CROSS APPLY T B 
where a.id = 3