2011-01-14 24 views
2

比方說,我有一個表叫my_table的,看起來像這樣:如何從同一個表中的父行獲取所有子項?

id  | name     | parent_id 
1  | Row 1     | NULL 
2  | Row 2     | NULL 
3  | Row 3     | 1 
4  | Row 4     | 1 
5  | Row 5     | NULL 
6  | Row 6     | NULL 
7  | Row 7     | 8 
8  | Row 8     | NULL 
9  | Row 9     | 4 
10  | Row 10     | 4 

基本上,我想我在PHP最終陣列看起來像這樣:

Array 
(
    [0] => Array 
     (
      [name] => Row 1 
      [children] => Array 
       (
        [0] => Array 
         (
          [name] => Row 3 
          [children] => 
         ) 

        [1] => Array 
         (
          [name] => Row 4 
          [children] => Array 
           (
            [0] => Array 
             (
              [name] => Row 9 
              [children] => 
             ) 

            [1] => Array 
             (
              [name] => Row 10 
              [children] => 
             ) 

           ) 

         ) 

       ) 

     ) 

    [1] => Array 
     (
      [name] => Row 2 
      [children] => 
     ) 

    [2] => Array 
     (
      [name] => Row 5 
      [children] => 
     ) 

    [3] => Array 
     (
      [name] => Row 6 
      [children] => 
     ) 

    [4] => Array 
     (
      [name] => Row 8 
      [children] => Array 
       (
        [0] => Array 
         (
          [name] => Row 7 
          [children] => 
         ) 

       ) 

     ) 

) 

所以,我希望它得到所有parent_id爲空的行,然後遞歸地查找所有嵌套的子節點。

現在,這裏是我遇到的麻煩的部分:

這怎麼可能用1個調用數據庫做了什麼?

我敢肯定,我可以用一個簡單的SELECT語句做到這一點,然後有PHP創建數組看起來像這樣,但我希望這可以用某種奇特的做DB連接或類似的東西。

回答

1

我不知道有任何方式從單個數據庫調用中獲得這樣的數組。一個mysql SQL查詢返回一個總是基於列的類表數據集。因此,答案是你不能

但是,它有可能使相當基於智能樹查詢。有關這方面的一個非常有趣的閱讀可以找到here

在其他系統比mysql,Common table expressions可以實現你想要的。

但是仍然沒有這樣的開箱即用的陣列。

0

AFAIK這是不可能的。除非你寫一些存儲過程來完成這項工作。

0

我不知道MySQL,但是在SQL Server(我相信這是ANSI-SQL),這是一個CTE(公共表表達式),它採用這種形式完成:

WITH MyCTE 
(
    -- Non-recursive anchor query 
    UNION ALL 
    -- Recursive portion that typically JOINs MyCTE to some other table 
) 
SELECT * FROM MyCTE; 
+0

遞歸查詢可在Oracle和PostgreSQL的最新爲好,但不是MySQL的。 – regilero 2011-01-14 21:48:25

0

這裏的問題在於,根據您要遍歷樹的順序來存儲Id。如果您通過構建樹一次,然後將所有節點複製回另一個表,根據遍歷節點的順序分配Id,解決此問題 - 下次只需掃描前向結果即可填充樹的選擇語句,如

SELECT * FROM my_table ORDER BY Id。

如果樹經常變化,則此解決方案將不起作用,因爲表必須重新生成。這可以通過將ID最初增加大數(例如1000)來解決,以便每次都不需要重新編號,因爲您可以從缺口分配新節點ID。如果樹的高度很小,對密鑰使用分數也可以很好地工作。

0

最簡單的方法就是在PHP中完成它。我不得不在Symfony中做類似的事情,但應該很容易閱讀和適應。從表格行中的數組開始。

public function executeGetTree(sfWebRequest $request) 
    { 
    $rows = Doctrine_Core::getTable('TreeNode')->findAll(); 
    $treeNodes = $rows->toArray(); 

    //set up new array to store children for each parent node 
    $nodesContainer = array(); 
    foreach ($treeNodes as $node){ 
     $parentId = $node['parent_id']; 
     //if node has no parent, it is a root node 
     $nodesContainer[isset($parentId)? $parentId : 'root'][] = $node; 
    } 

    $tree = array(); 
    //recursively get descendents for each root node 
    foreach($nodesContainer['root'] as $rootNode) 
    { 
     $tree[] = $this->getChildren($nodesContainer, array($rootNode)); 
    } 

    print_r($tree); 

    return sfView::NONE; 
    } 

    private function getChildren(&$container, $parentNode){ 
     $children = array(); 
     foreach ($parentNode as $node){ 
      if(isset($container[$node['id']])){ 
      $node['children'] = $this->getChildren($container, $container[$node['id']]); 
      } 
      $children[] = $node; 
     } 
     return $children; 
    } 
0

我希望這可以用某種奇特DB連接或類似的東西來完成。

你應該考慮聽起來有多不可能。 僅考慮樹中的一個分支,從1→4→9 您將如何可視化MySql結果或任何DBMS中單行中的關係。

我能想到的層次結果的唯一明智的選擇是XML,但您不想去那裏,因爲它可以在基於record.parent結構的基礎結構上更好地完成,而不是解析XML。

0

也許這樣的事情,添加水平爲相應:

SELECT 
    d1.*, 
    d2.`name` AS '2nd Level', 
    d3.`name` AS 'Top Level' 
    FROM `my_table` AS d1 
    LEFT JOIN `my_table` AS d2 ON d1.parent_id=d2.id 
    LEFT JOIN `my_table` AS d3 ON d2.parent_id=d3.id 
相關問題