PHP / MySQL邻接列表问题

时间:2011-07-13 14:02:11

标签: php mysql recursion adjacency-list

我有以下问题:对邻接列表进行映像,这已经过了一个递归 来自像这样的SQL

SELECT * FROM pages as ps  ORDER BY COALESCE(child_of,page_id), page_id LIMIT x,y

 public static function tree(&$arr, $id = NULL) {

    $result = array();

    foreach ($arr as $a) {

        if ($id == $a['child_of']) {

            $a ['children'] = self::tree($arr, $a['page_id']);

            $result[] = $a;
        }

    }

    return $result;
}

到目前为止,这么好 - 与另一个“flattener”我正在得到我需要的地方。现在,这是诀窍, 这适用于“分页”结果,并且可能发生的事情(并且它确实发生)是父项可以在一个子集中,而子项在不同的子集中。随着上面的递归是显而易见的 孩子不会在缺少父母的情况下到达树上。

关于如何解决这个问题的任何想法? 非常感谢帮助。

2 个答案:

答案 0 :(得分:1)

关系表中的分层数据,我们都不喜欢它吗?

使用您当前的数据库布局,您只能通过始终获取所有节点或执行与嵌套级别一样多的JOINS来解决您的问题,对所有内容进行正确排序(您的排序方式只会产生这个基本问题) ,你有,不太重要)。

在您提出之前,您应这样做。

您拥有的另一种方法是选择一个完全不同的模型来创建层次结构:

  • 嵌套集
  • 所有节点之间的上升/后代关系。

见幻灯片48及以下。 here

答案 1 :(得分:1)

一个很好的阅读开始是Hierarchical Data In MySQL (我以前可以在MySQL.com网站上找到,arghh)

读它?

以下是如何使用邻接列表模型完成的。但仅适用于已知固定数量的嵌套 (此示例为四个嵌套级别)

我会找出哪些网页是根页(树的)。然后只选择那些带有查询的人。将LIMIT x,x放在此select语句中。

之后,以下语句:(或类似的东西)

string query = "
    SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
    FROM category AS t1
    LEFT JOIN category AS t2 ON t2.parent = t1.category_id
    LEFT JOIN category AS t3 ON t3.parent = t2.category_id
    LEFT JOIN category AS t4 ON t4.parent = t3.category_id
    WHERE t1.name IN('ELECTRONICS', '<some other name>');
";

可以返回这样的内容:

+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS          | TUBE         | NULL  |
| ELECTRONICS | TELEVISIONS          | LCD          | NULL  |
| ELECTRONICS | TELEVISIONS          | PLASMA       | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS  | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS   | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL  |
| etc...      | etc...               | etc...       |       |
+-------------+----------------------+--------------+-------+

诀窍是在查询的IN()语句中仅使用限制(或ID,如果需要)的查询的根名称。

这应该表现得相当不错(理论上)

上述查询的原理也可以用来找出树的根中有多少后代(有一点GROUP BYCOUNT()魔法;)此外,你可以找出你的哪些页面是根据这个原则(虽然出于性能原因我会将其保存在tabledata中)

如果您想要动态数量的嵌套 (几乎无限扩展),那么实现nested set将是最佳选择。