2016-09-27 34 views
0

我試圖讓我的頭在PHP/MySQL特別是Codeigniter中使用封閉表,我正在建設的應用程序有區域,每個區域可以有一些地點,部門等插入與PHP/MySQL的封閉表

我一直在使用http://www.slideshare.net/billkarwin/models-for-hierarchical-data瞭解它是如何工作的。

而且我也一直在使用https://gist.github.com/dazld/2174233來幫助我掌握訪問數據的方法,我可以做的很好,我已經調整了方法來根據需要提取數據,這很好。

但現在我試圖插入數據,我不能得到我的頭。所以我改編自上面的腳本add方法,但我不明白,我不能讓它的工作

繼承人的範圍表

+------------+-------------+------+-----+---------+----------------+ 
| Field  | Type  | Null | Key | Default | Extra   | 
+------------+-------------+------+-----+---------+----------------+ 
| area_id | int(11)  | NO | PRI | NULL | auto_increment | 
| area_title | varchar(40) | NO |  | NULL |    | 
| area_name | varchar(40) | NO |  | NULL |    | 
| org_id  | int(11)  | NO |  | NULL |    | 
+------------+-------------+------+-----+---------+----------------+ 

繼承人的area_hierarchy表

+------------+---------+------+-----+---------+----------------+ 
| Field  | Type | Null | Key | Default | Extra   | 
+------------+---------+------+-----+---------+----------------+ 
| id   | int(11) | NO | PRI | NULL | auto_increment | 
| ancestor | int(11) | NO |  | NULL |    | 
| descendant | int(11) | NO |  | NULL |    | 
| lvl  | int(11) | NO |  | NULL |    | 
+------------+---------+------+-----+---------+----------------+ 

繼承人的方法,我試圖用添加條目:

public function add($node_id, $target_id) { 

    $sql = 'SELECT ancestor, '.$node_id.', lvl+1 
      FROM area_hierarchy 
      WHERE descendant = '.$target_id.' 
      UNION 
      SELECT '.$node_id.','.$node_id.',0'; 

    $query = 'INSERT INTO area_hierarchy (ancestor, descendant,lvl) ('.$sql.')'; 

    $result = $this->db->query($query); 

    return $result; 

} 

那麼具體的,什麼是$ node_id和$ target_id。

什麼是lvl + 1?

所以,如果我添加一個新的頂級區域,我傳遞給這個方法的數據是什麼?

查詢也將失敗,並給出UNION

+1

節點ID是您要添加的新節點(子),目標ID是父節點(祖先)。工會要處理自我引用,你應該始終關閉自我引用。如果我想在B下添加D,我需要選擇B的所有祖先並創建與D的關係,我還需要根據D = D的級聯爲零創建自引用。 –

+1

在你的例子中,假設你有10個區域,1,2,3,4,5,它們有完全相同的主鍵。它們應該都存在於根級別上,你可以首先添加這些區域,然後你可以爲每個節點調用'add($ areaId)'。然後你希望6,7,8成爲3的孩子。然後你可以爲每個區域調用'add($ areaId,3)'。最後,我們希望9和10是8的孩子。我們調用'add($ areaId,8)'。如果您需要關於爲什麼您的查詢失敗或未按預期工作的幫助,則需要向我們提供錯誤和預期結果。 –

+0

謝謝,很好的解釋。我會離開和體驗 – frobak

回答

1

$node_id後一個語法錯誤,就會從areaarea_id列的值。據推測,這是剛剛添加到區域表中的一行。

$target_id將作爲area表中另一行的area_id列的值,該行是您標識爲「父」的行,即直接祖先。

lvl+1是層次結構中的世代或層次......後代與其父代的「遠」程度。

如果您要添加新的「頂級」區域,您可以使用$node_id代替$target_id

瞭解這一點的最佳方法之一是查看area_hierarchy表的「當前狀態」以及添加節點時表的「結束狀態」。

只需在樹中的頂級節點,AREA_ID = 11,area_hierarchy表是這樣的:

ancestor descendant lvl 
-------- ---------- --- 
11  11   0 

如果再加上另一行區域分配表,AREA_ID = 22,作爲一個孩子AREA_ID = 11(嫡系),我們需要添加這兩個行area_hierarchy:

ancestor descendant lvl 
-------- ---------- --- 
11  22   1 
22  22   0 

如果再加上另一行區表,AREA_ID = 333,作爲AREA_ID = 22的孩子,我們需要將這些行添加到area_hierarchy表中:

ancestor descendant lvl 
-------- ---------- --- 
11  333  2 
22  333  1 
333  333  0 

請注意,我們需要添加的前兩行看起來很像表中已存在的行,其中後代= 22。區別在於新行的後代是333而不是22,lvl的值比我們在表中已經有的行多一個。

我們需要添加的第三行是對自身的引用。就像我們將area_id = 11作爲自己的「父母」一樣。

我們從UNION之後的部分得到第三行。前兩行是通過複製area_hierarchy中的行,將後代列的值替換爲我們添加的節點的標識(333),並將lvl增加1.

一旦您瞭解了哪些行需要添加,以及我們如何通過複製/修改表中的其他行來派生它們,然後SQL開始有意義。


您將完成添加這三行的AREA_ID = 333,調用add函數:如果你想添加AREA_ID = 4444的層次結構中的一個新的 「頂級」

add(333,22); 

add(4444,4444); 
+0

感謝您的提問,非常翔實並且清楚。現在我還有另外一個問題了,我是否應該將列表索引到列表中,比如說組織的ID? – frobak

+0

@frobak:是的,添加適當的索引。索引有幾個重要的目的。首先,索引可以用來強制執行唯一的約束。如果您希望數據庫阻止將重複行添加到表中,您將添加一個唯一約束。考慮例如執行第二個調用'add(4444,4444)'。你想在數據庫中結束什麼狀態?你想在area_hierarchy表中有兩個*相同的行嗎?索引的另一個目的是提高性能。哪些索引最適合取決於哪​​些語句將被執行。 – spencer7593