订购具有父子关系的评论的分层查询?
Order hierarchical query for comments with parent-child relation?
我有一个使用 adjacency list
存储分层数据的评论系统(我相信),例如:MySql table 有列 id
,parent_id
, date
, ... ,其中没有 parent_id
的评论是主要评论,带有 parent_id
的评论自然是回复。
在初始页面加载时,我进行了一个 Ajax 调用,加载了所有没有 parent_id
的评论,因此所有主要评论。
SELECT * FROM comms WHERE parent_id IS NULL
现在,如果任何评论有回复,该评论会出现 "load replies" 之类的按钮,点击后会进行另一个调用,加载所有 parent_id
评论 [=13] 的评论=],然后递归查询加载回复的回复等等。这很好用,问题是从它们的加载顺序来看,你无法真正分辨出什么是重播。
所以我想要的是订购它们,以便重播在它所属的评论下。
现在只有 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 ?
如果我使用我喜欢的答案中提供的"Alternative 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 个不同的表中,
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);
同评论回复主评论的回复
由于这需要递归,而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 开始,将获取所有 top-level 评论(parent_id = NULL 的评论),递归将显示所有回复按日期顺序排列,但也按 parents 的顺序排列(无论是评论还是回复)。
您还可以添加一个 "level" 参数来设置输出样式:
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>
我在 MSSQL 上工作,我非常确定 CROSS APPLY 会对您有所帮助。我假设 MYSQL 确实有 join .
例如
SELECT A.PARENT_ID,A.COMMENT,* FROM T A
CROSS APPLY T B
where a.id = 3
我有一个使用 adjacency list
存储分层数据的评论系统(我相信),例如:MySql table 有列 id
,parent_id
, date
, ... ,其中没有 parent_id
的评论是主要评论,带有 parent_id
的评论自然是回复。
在初始页面加载时,我进行了一个 Ajax 调用,加载了所有没有 parent_id
的评论,因此所有主要评论。
SELECT * FROM comms WHERE parent_id IS NULL
现在,如果任何评论有回复,该评论会出现 "load replies" 之类的按钮,点击后会进行另一个调用,加载所有 parent_id
评论 [=13] 的评论=],然后递归查询加载回复的回复等等。这很好用,问题是从它们的加载顺序来看,你无法真正分辨出什么是重播。
所以我想要的是订购它们,以便重播在它所属的评论下。
现在只有 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 ?
如果我使用我喜欢的答案中提供的"Alternative 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 个不同的表中,
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);
同评论回复主评论的回复
由于这需要递归,而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 开始,将获取所有 top-level 评论(parent_id = NULL 的评论),递归将显示所有回复按日期顺序排列,但也按 parents 的顺序排列(无论是评论还是回复)。
您还可以添加一个 "level" 参数来设置输出样式:
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>
我在 MSSQL 上工作,我非常确定 CROSS APPLY 会对您有所帮助。我假设 MYSQL 确实有 join .
例如
SELECT A.PARENT_ID,A.COMMENT,* FROM T A
CROSS APPLY T B
where a.id = 3