SQL中使用PHP进行无限自连接?

时间:2012-12-11 15:01:46

标签: php sql select

有一个像这样的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 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分: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字段的正确方法。

答案 2 :(得分: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排序,以获得一个很容易转换为树的数组。

答案 3 :(得分:0)

我不知道单个查询,但是如何在该表中添加isChildren列?

这样你就会收到要删除的评论的ID,将其存储在$ idToDelete中并删除id等于你收到的id的评论,删除它,将其parentId保存在$ idToDelete中等。 你可以在一段时间内做到这一点,检查列isChildren是否正确。如果isChildren为false,则删除该注释的第一个父项及其所有子项。

应该不应该工作吗? Dunno如果修改数据库是一个选择。