1

我正在为 MySQL 和 PHP 开发线程评论系统。我选择了 Closure Table 模式,但我有问题。我需要查询(查询)来获取整棵树。怎么做?我对此进行了很多搜索,但找不到任何最佳选择。如果您有更好的主题评论,请告诉我。谢谢你的回复。

4

3 回答 3

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>';
}

另一方面,嵌套集模型不是评论系统的好解决方案,因为插入和更新量很高。如果您的数据很少更新,这是一个有效的解决方案。

于 2011-09-20T14:59:21.027 回答
2

这是我到目前为止所拥有的:

SELECT `Comments`.* FROM `Comments`
LEFT JOIN `TreePaths` ON `Comments`.`iD` = `TreePaths`.`descendant`
WHERE `TreePaths`.`ancestor` = <Root ID>

这会将给定树的所有节点从关闭表中拉出,但目前它们的排序不正确。如果我弄清楚最后一部分,我会更新这篇文章。以编程方式,您可以使用结果集中的信息获得正确的顺序,但我希望它在结果中是正确的。

于 2011-11-27T17:37:21.963 回答
1

我遇到了您的问题,因为我也在查看闭包表。我认为如果您遵循 Bill Karwin 在他的“Sql 反模式”一书中关于闭包表的建议,您的问题就可以解决:

为树中共享祖先/后代关系的每一对节点在此表中存储一行, 即使它们在树中被多个级别分隔

(我的重点)

因此,一个查询parentId将一次性生成父级的所有子级。(在 SQL Server 中,这可以通过递归查询来完成)。

和:

您可以改进 Closure Table 以更轻松地查询直接父节点或子节点。将 TreePaths.path_length 属性添加到 Closure Table 设计中。

即:将项目之间的距离存储在闭包表中。

我想你会很喜欢他的例子。这也与评论线程有关。

于 2011-12-08T15:34:33.317 回答