0

有一个这样的 SQL 表:

+----+-----------+----------+
| ID | Comment   | ParentID |
+----+-----------+----------+
|  1 | Some Text |        0 |
|  2 | Some Text |        0 |
|  3 | Some Text |        2 |
|  4 | Some Text |        2 |
|  5 | Some Text |        3 |
|  6 | Some Text |        3 |
|  7 | Some Text |        1 |
+----+-----------+----------+

这是一篇博客文章的评论和一些子评论。子级的深度是无限的:每个子评论都可以有另一个子评论。

用户现在想删除 ID 为 2 的父评论。所以我需要一个 SQL 查询,它选择所有子评论 ID(和子评论等)。

目前我有这个查询,它只选择子评论的第一级:

SELECT ID
FROM comment_table
WHERE ParentID = 2

是否可以在一个查询中选择所有这些子评论?

4

4 回答 4

1

我更喜欢使用的一个解决此问题的方法是添加“物化路径”。

您只需要添加一个包含对象的整个祖先的列。例如,您的表格调整如下:

+----+-----------+----------+----------+
| ID | Comment   | ParentID | TreePath |
+----+-----------+----------+----------+
|  1 | Some Text |        0 |          |
|  2 | Some Text |        0 |          |
|  3 | Some Text |        2 |       -2-|
|  4 | Some Text |        2 |       -2-|
|  5 | Some Text |        3 |     -2-3-|
|  6 | Some Text |        3 |     -2-3-|
|  7 | Some Text |        1 |       -1-|
+----+-----------+----------+----------+

选择 2 的所有后代如下所示:

SELECT ID FROM comment_table WHERE TreePath LIKE '-2-%'

如果你想在 PHP 中构建一个注释树,你甚至可以通过排序TreePath得到一个相当容易转换为树的数组。

于 2014-04-26T23:27:02.117 回答
1

你可以用一个简单的递归函数在 PHP 中做到这一点:

function child_comments($id,&$arr) {
   $sql = 'SELECT ID, Comment, ParentID FROM comment_table WHERE ParentID='.$id;
   // get rows for $sql
   foreach ($rows as $row) {
      $arr[] = $row;
      child_comments($row['id'],$arr);
   }
}
child_comments(2,$comments);

$comments将保存一系列评论 2 的孩子,它是孩子的​​孩子等等......

上述代码被视为伪代码,需要进行调整以适应您从数据库(pdo、mysqli、mysql_*)中检索数据的方式。

特别// get rows for $sql需要用相关代码替换以获取$sql.

递归调用child_comments可能还需要根据从数据库返回的行的结构进行调整,这$row['id']可能不是访问ID字段的正确方式。

于 2012-12-11T15:48:15.737 回答
1

这是一个常见问题,鉴于您的数据库结构并没有真正好的答案,因为大多数 SQL 数据库不支持递归查询,因此您要么需要执行很多很多查询(这很糟糕),要么限制嵌套(也不好)。

有一些解决方案,但它们涉及备用数据库模式。Bill Karwin 写了一些关于 PHP/MySQL 中分层数据问题的文章。他在这里有一个演讲:http ://www.percona.tv/percona-webinars/models-for-hierarchical-data-in-sql-and-php他讨论了一些选项。他还在他的书(SQL 反模式)中写了博客并撰写了有关不同选项及其优缺点的章节。

于 2012-12-11T15:17:56.137 回答
0

我不知道单个查询,但是在该表中添加一个 isChildren 列怎么样?

这样,您将收到要删除的评论的 id,将其存储在 $idToDelete 中,并删除 id 等于您收到的 id 的评论,删除它,将其 parentId 保存在 $idToDelete 中,等等。您可以在一个检查列 isChildren 是否为真的 while 块。如果 isChildren 为 false,则您删除了该评论的第一个父级及其所有子级。

那应该工作不应该吗?不知道是否可以选择修改数据库。

于 2012-12-11T15:17:56.507 回答