2009-03-10 8 views
0

私はデータベースのテーブルからツリー構造を生成しようとしています。テーブルはフラットに格納され、各レコードは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); 
     }    
    } 
} 

。誰でも手伝ってくれますか?

+0

あなたは、ほとんどの作業とはどういう意味ですか?何が効いているの? – markus

+0

スマートな方法を質問する方法:http://www.catb.org/~esr/faqs/smart-questions.html – mozboz

答えて

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

注意一般的にデータベースへのラウンドトリップを最小限に抑えたいからです(あなたが非常に大きなツリーを持っている場合など、それを行う方法がより最適であるいくつかのユースケースがあり、小さなその部分は、しかし、私はここでそれが疑わしい)

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句を取り除く。一度にテーブル全体を読む。ツリーを2度目に処理する必要があります。まず、データベースを配列のリストに読み込みます。次に、出力を行うために配列を再帰的に処理します。

あなたの配列は次のようになります。

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 
4

ほとんどの場合、現在のパスを続行しないでください。あなたのツリーがさらに大きくなっても、使用しようとしている再帰的な方法はあなたのパフォーマンスをほぼ確実に殺します。ツリーを頻繁に読み込む予定の場合は、隣接リストの代わりにネストされたセット構造を調べるべきでしょう。

ネストされたセットを使用すると、単一のクエリで適切にネストされたツリー全体を簡単に取得できます。

木の説明については、これらの質問を参照してください。

Is it possible to query a tree structure table in MySQL in a single query, to any depth?

Implementing a hierarchical data structure in a database

What is the most efficient/elegant way to parse a flat table into a tree?