2011-09-02 15 views

回答

2

事實證明,關係數據庫在處理樹木可怕。嘗試一種不同的存儲數據的方法可能會更好。如果你對這個模式有自己的想法,那麼你基本上有三個選擇,其中沒有一個是非常好的。

選項1:

如果你知道你的樹的根,知道樹的深度:

SELECT uid, value, parent_uid 
FROM your_table level1 
LEFT JOIN your_table level2 ON uid = parent_uid 
    ON level1.uid = level2.uid 
LEFT JOIN your_table level2 ON uid = parent_uid 
    ON level3.uid = level3.uid 
/* repeat the join until you have gone enough levels down */ 
WHERE uid = 7 /* or whatever the uid is */ 
ORDER BY parent_uid, uid 

你可以用這個來獲取被認爲是在一切樹根,並在PHP中重建它。 這個選項很糟糕,因爲它很慢並且不靈活。

選項2

如果您知道樹的根,而不是深度:

<?php 
$root_id = 7; 
$id_list = array($root_id); 
$tree = array(); 
while (!empty($id_list)) { 
    $new_list = array(); 
    foreach ($id_list as $id) { 
     $query = "SELECT * FROM your_table WHERE parent_uid = '$id'"; 
     $results = mysql_query($query); 
     while ($next = mysql_fetch_array($results)) { 
      array_push($new_list, $next['uid']); 
     } 
     // find the item in $tree and add it, also ugly 
    } 
    $id_list = $new_list; 
} 
echo json_encode($tree); 

儘管是更靈活的這個選項是比較慢和醜陋。

方案3:

<?php 
$query = "SELECT * FROM your_table ORDER BY parent_uid"; 
$result = mysql_query($query); 
$tree = array(); 
while ($next = mysql_fetch_array($result)) { 
    // attach the item to $tree, this is slow and/or ugly code 
} 
echo json_encode($tree); 
?> 

此代碼需要你從MySQL獲得整個表,再加上它是一種緩慢的。

結論:

我沒有測試這些代碼樣本,因爲它們都吸。 查找樹的另一種存儲方法。 SQL只是爲了這個工作。 您可能會考慮將其保存在xml或json中,除非數據集太大,在這種情況下,您需要爲此任務設計存儲引擎。

+0

+1的信息,雖然你看起來有點悲觀。 SQL Server有這樣的事情的公共表表達式,它似乎在MySQL中沒有模擬。但肯定有辦法做到這一點;有許多應用程序需要某種分層結構(例如,任何帶有樹形菜單或站點地圖的數據驅動的應用程序)。 –

+0

對於悲觀主義者,我大部分時間都是在與這個問題作鬥爭時遺留下來的。正如這些示例所示,它當然可以完成,但SQL無法遍歷樹。對於SQL引擎未知的n級連接是非常類似的。任何使用標準SQL的東西要麼很慢,要麼很複雜,可能兩者都有。我只是建議採取不同的方法。 – regality

+0

我會嘗試第二個選項。謝謝 –

0

查看包含在PHP中的json_encode函數。該函數將從給定的數組中創建一個JSON對象。

文檔中的示例應該提供充足的幫助。

+1

它不僅僅是一個數組,它是一棵樹。 –

2

當我發佈我的第一個答案時,我想我會說服你找到一種不同的方法。由於沒有做到這一點,並癡迷於酷遞歸算法,這裏是基於我以前的答案中的選項2的工作解決方案。

對於樹中的每個節點,這將對mysql_query進行一次調用,這對性能來說是非常糟糕的,所以不要期望它能很好地擴展,但對於輕量級使用來說不會太慢。

你將不得不使用to_array()函數來使json完全按照你想要的方式運行,但是這應該讓你離開地面。

<?php 

Class Node { 
    public $id; 
    public $parent_id; 
    public $value; 
    public $children; 
    public $depth; 

    function __construct($id, $parent_id, $value) { 
     $this->id = $id; 
     $this->parent_id = $parent_id; 
     $this->value = $value; 
     $this->children = array(); 
     $this->depth = 0; 
    } 

    function get_children_from_mysql() { 
     $query = "SELECT * FROM your_table WHERE parent_uid = '$this->id'"; 
     $results = mysql_query($query); 
     while ($next = mysql_fetch_array($results)) { 
     $next_node = new Node($next['uid'], $next['parent_uid'], $next['value']); 
     $this->children[$next_node->id] = $next_node; 
     $next_node->get_children_from_mysql(); 
     } 
    } 

    function to_array() { 
     if (count($this->children) > 0) { 
     $arr = array(); 
     foreach ($this->children as $child) { 
      array_push($arr, $child->to_array()); 
     } 
     return array($this->value => $arr); 
     } else { 
     return $this->value; 
     } 
    } 

    function to_json() { 
     return json_encode($this->to_array()); 
    } 

} 

// you need to know the root uid/value or get it from mysql 
$root_uid = 1; 
$root_value = "root node value"; 
$root = new Node($root_uid, 0, $root_value); 
$root->get_children_from_mysql(); // magical recursive call 

echo $root->to_json(); 

?>