我正在为MySQL和PHP开发线程评论系统。我选择了Closure Table模式,但我有问题。我需要查询(查询)才能获得整棵树。怎么做?我已经搜索了很多关于这一点,但我发现没有什么是最佳的。如果你有更好的线程评论,请告诉我。 Tnanks为您的回复。
答案 0 :(得分:2)
如果此用例在您的应用程序中是常见的,只需存储根id(树的根的id。这可以是这些注释所属的帖子的ID)。现在,当您需要获取整个评论树时,您只需要执行以下操作:
SELECT * FROM comments WHERE root_id = <root_id>
或您设计的等效查询。如果您提供表格定义,我可以帮助您解决具体问题。
更新
$dbh = new PDO($dsn, $user, $password);
$sql = "SELECT A.*, GROUP_CONCAT(descendant) as descendants FROM Comments AS A INNER JOIN Paths AS B ON A.id = B.ancestor WHERE A.item = ? GROUP BY A.id";
$stmt = $dbh->prepare($sql);
$stmt->execute(array($item));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$adjacency_list = array(); $comments = array();
foreach($data as $row) {
$comments[$row['id']] = $row;
$descendants = explode(',', $row['descendants']);
$adjacency_list[$row['id']] = $descendants;
}
echo '<UL>';
foreach($adjacency_list[$item] as $top_level_comment) {
printTree($top_level_comment, $adjacency_list[$top_level_comment]);
}
echo '</UL>';
function printTree($node, $descendants) {
echo '<LI>'.$node;
if(sizeof($descendants) > 0) {
echo '<UL>';
foreach($descendants as $descendant) {
$d = array();
if(!empty($adjacency_list[$descendant])) $d = $adjacency_list[$descendant];
printTree($descendant, $adjacency_list[$descendant]);
}
echo '</UL>';
}
echo '</LI>';
}
另一方面,嵌套集模型由于高插入和更新而不是评论系统的好解决方案。如果您的数据很少更新,这是一种有效的解决方案。
答案 1 :(得分:2)
这是我到目前为止所做的:
SELECT `Comments`.* FROM `Comments`
LEFT JOIN `TreePaths` ON `Comments`.`iD` = `TreePaths`.`descendant`
WHERE `TreePaths`.`ancestor` = <Root ID>
这将从闭包表中提取给定树的所有节点,但目前它们没有正确排序。如果我弄清楚最后一部分,我会更新这篇文章。以编程方式,您可以使用结果集中的信息获得正确的顺序,但我希望它在结果中是正确的。
答案 2 :(得分:1)
我遇到了你的问题,因为我也在关注关闭表。我认为如果你在他的书“Sql anti-patterns”中遵循Bill Karwin关于闭包表的建议,你的问题就可以解决了:
在此表中为每个存储一行 树中的一对节点共享一个祖先/后代关系, 即使它们在树中被多个级别分隔。
(我的重点)
因此,对parentId
的一个查询将一次性产生父母的所有子女。 (在SQL Server中,这可以通过递归查询来完成)。
和
您可以改进Closure Table以立即进行查询 父节点或子节点更容易。添加TreePaths.path_length属性 关闭表设计。
即:存储闭包表中项目之间的距离。
我觉得你真的很喜欢他的榜样。这也是评论主题。