简体   繁体   English

如何从数据库中的表生成树结构?

[英]How can I generate a tree structure from a table in a database?

I'm trying to generate a tree structure from a table in a database.我正在尝试从数据库中的表生成树结构。 The table is stored flat, with each record either having a parent_id or 0. The ultimate goal is to have a select box generated, and an array of nodes.该表是扁平存储的,每条记录都有一个 parent_id 或 0。最终目标是生成一个 select 框和一个节点数组。

The code I have so far is:我到目前为止的代码是:

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

It's almost working, but not quite.它几乎可以工作,但不完全。 Can anybody help me finish it off?谁能帮我完成它?

You almost certainly, should not continue down your current path.你几乎可以肯定,不应该继续你目前的道路。 The recursive method you are trying to use will almost certainly kill your performance if your tree ever gets even slightly larger.如果您的树变得稍微大一点,您尝试使用的递归方法几乎肯定会破坏您的性能。 You probably should be looking at a nested set structure instead of an adjacency list if you plan on reading the tree frequently.如果您打算经常阅读树,您可能应该查看嵌套集结构而不是邻接列表。

With a nested set, you can easily retrieve the entire tree nested properly with a single query.使用嵌套集,您可以使用单个查询轻松检索正确嵌套的整个树。

Please see these questions for aa discussion of trees.有关树的讨论,请参阅这些问题。

Is it possible to query a tree structure table in MySQL in a single query, to any depth? 是否可以在单个查询中查询 MySQL 中的树结构表到任何深度?

Implementing a hierarchical data structure in a database 在数据库中实现分层数据结构

What is the most efficient/elegant way to parse a flat table into a tree? 将平面表解析为树的最有效/优雅的方法是什么?

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

This line is destroying your ORDER BY display_order.此行正在破坏您的 ORDER BY display_order。 Change it to将其更改为

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

My next issue is the $row->parent_category_id part of that.我的下一个问题是其中的 $row->parent_category_id 部分。 Shouldn't it just be $row->parent_id?不应该只是 $row->parent_id 吗?

EDIT: Oh, I didn't read your source closely enough.编辑:哦,我没有仔细阅读你的资料。 Get rid of the WHERE clause.摆脱 WHERE 子句。 Read the whole table at once.一次阅读整个表格。 You need to post process the tree a second time.您需要再次对树进行后期处理。 First you read the database into a list of arrays.首先将数据库读入 arrays 列表。 Then you process the array recursively to do your output.然后递归处理数组以执行 output。

Your array should look like this:您的数组应如下所示:

 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

I think it's this line here:我认为这是这条线:

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

should be:应该:

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

You are only indenting it once, not the number of times it should be indented.你只是缩进一次,而不是它应该缩进的次数。

And this line:而这一行:

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

should be:应该:

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

Note that you should probably follow the advice in the other answer though, and grab the entire table at once, and then process it at once, because in general you want to minimize round-trips to the database (there are a few use cases where the way you are doing it is more optimal, such as if you have a very large tree, and are selecting a small portion of it, but I doubt that is the case here)请注意,您可能应该遵循另一个答案中的建议,一次抓取整个表,然后立即处理它,因为通常您希望最大限度地减少到数据库的往返行程(有一些用例你这样做的方式更优化,例如如果你有一棵非常大的树,并且正在选择它的一小部分,但我怀疑这里的情况)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM