1

我正在尝试从数据库中的表生成树结构。该表是扁平存储的,每条记录都有一个 parent_id 或 0。最终目标是生成一个选择框和一个节点数组。

我到目前为止的代码是:

function init($table, $parent_id = 0) 
{

    $sql = "SELECT id, {$this->parent_id_field}, {$this->name_field} FROM $table WHERE {$this->parent_id_field}=$parent_id ORDER BY display_order";

    $result = mysql_query($sql);

    $this->get_tree($result, 0);

    print_r($this->nodes);
    print_r($this->select);
    exit;
}

function get_tree($query, $depth = 0, $parent_obj = null)
{   
    while($row = mysql_fetch_object($query))
    {   
        /* Get node */
        $this->nodes[$row->parent_category_id][$row->id] = $row;

        /* Get select item */
        $text = "";
        if($row->parent_category_id != 0) {
            $text .= "    ";
        }
        $text .= "$row->name";
        $this->select[$row->id] = $text;

        echo "$depth $text\n";

        $sql = "SELECT id, parent_category_id, name FROM product_categories WHERE parent_category_id=".$row->id." ORDER BY display_order";

        $nextQuery = mysql_query($sql);
        $rows = mysql_num_rows($nextQuery);

        if($rows > 0) {
            $this->get_tree($nextQuery, ++$depth, $row);
        }            
    }
}

它几乎可以工作,但不完全。谁能帮我完成它?

4

3 回答 3

4

你几乎可以肯定,不应该继续你目前的道路。如果您的树变得稍微大一点,您尝试使用的递归方法几乎肯定会破坏您的性能。如果您打算经常阅读树,您可能应该查看嵌套集结构而不是邻接列表。

使用嵌套集,您可以使用单个查询轻松检索正确嵌套的整个树。

有关树的讨论,请参阅这些问题。

是否可以在单个查询中查询 MySQL 中的树结构表到任何深度?

在数据库中实现分层数据结构

将平面表解析为树的最有效/优雅的方法是什么?

于 2009-03-10T19:00:17.670 回答
1
    $this->nodes[$row->parent_category_id][$row->id] = $row;

此行正在破坏您的 ORDER BY display_order。将其更改为

    $this->nodes[$row->parent_category_id][] = $row;

我的下一个问题是其中的 $row->parent_category_id 部分。不应该只是 $row->parent_id 吗?

编辑:哦,我没有仔细阅读你的资料。摆脱 WHERE 子句。一次阅读整个表格。您需要再次对树进行后期处理。首先,您将数据库读入数组列表。然后你递归地处理数组来做你的输出。

您的数组应如下所示:

 Array(0 => Array(1 => $obj, 5 => $obj), 
       1 => Array(2 => $obj),
       2 => Array(3 => $obj, 4 => $obj),
       5 => Array(6 => $obj) );

 function display_tree() {
      // all the stuff above
      output_tree($this->nodes[0], 0); // pass all the parent_id = 0 arrays.
 }

 function output_tree($nodes, $depth = 0) {
     foreach($nodes as $k => $v) {
         echo str_repeat(' ', $depth*2) . $v->print_me();
         // print my sub trees
         output_tree($this->nodes[$k], $depth + 1);
     }
 }

 output:
 object 1
   object 2
     object 3
     object 4
 object 5
   object 6
于 2009-03-10T16:56:32.553 回答
0

我认为这是这条线:

if($row->parent_category_id != 0) {
    $text .= "    ";
}

应该:

while ($depth-- > 0) {
    $text .= "    ";
}

你只是缩进一次,而不是它应该缩进的次数。

而这一行:

$this->get_tree($nextQuery, ++$depth, $row);

应该:

$this->get_tree($nextQuery, $depth + 1, $row);

请注意,您可能应该遵循另一个答案中的建议,一次抓取整个表,然后立即处理它,因为通常您希望最大限度地减少到数据库的往返行程(有一些用例你这样做的方式更优化,例如如果你有一棵非常大的树,并且正在选择它的一小部分,但我怀疑这里的情况)

于 2009-03-10T18:21:35.720 回答