2011-06-09 44 views
7

我決定關注http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1ch20.html在MySQL中處理嵌套集?

所以現在我正在尋找一些幫助的代碼。

我使用他們的數據,我的測試, 所以,我想象的樹是像這樣:

array('value' => 'Richard Shakespeare', 
     array('value' => 'Henry', 
      array('value' => 'Joan'), 
      array('value' => 'Margaret'), 
      array('value' => 'William', 
       array('value' => 'Susana', 
        array('value' => 'Elizabeth Hall', 
         array('value' => 'John Bernard'))), 
       array('value' => 'Hamnet'), 
       array('value' => 'Judith', 
        array('value' => 'Shakespeare Quiney'), 
        array('value' => 'Richard Quiney'), 
        array('value' => 'Thomas Quiney'))), 
      array('value' => 'Gilbert'), 
      array('value' => 'Joan', 
       array('value' => 'William Hart'), 
       array('value' => 'Mary Hart'), 
       array('value' => 'Thomas Hart'), 
       array('value' => 'Micheal Hart')), 
      array('value' => 'Anne'), 
      array('value' => 'Richard'), 
      array('value' => 'Edmond')), 
     array('value' => 'John')); 

所以,如果我們要插入到我們希望與

落得數據庫
Array 
(
    [0] => Array 
     (
      [value] => Richard Shakespeare 
      [left] => 1 
      [right] => 46 
     ) 

    [1] => Array 
     (
      [value] => Henry 
      [left] => 2 
      [right] => 43 
     ) 

    [2] => Array 
     (
      [value] => Joan 
      [left] => 3 
      [right] => 4 
     ) 

    [3] => Array 
     (
      [value] => Margaret 
      [left] => 5 
      [right] => 6 
     ) 

    [4] => Array 
     (
      [value] => William 
      [left] => 7 
      [right] => 24 
     ) 

    [5] => Array 
     (
      [value] => Susana 
      [left] => 8 
      [right] => 13 
     ) 

    [6] => Array 
     (
      [value] => Elizabeth Hall 
      [left] => 9 
      [right] => 12 
     ) 

    [7] => Array 
     (
      [value] => John Bernard 
      [left] => 10 
      [right] => 11 
     ) 

    [8] => Array 
     (
      [value] => Hamnet 
      [left] => 14 
      [right] => 15 
     ) 

    [9] => Array 
     (
      [value] => Judith 
      [left] => 16 
      [right] => 23 
     ) 

    [10] => Array 
     (
      [value] => Shakespeare Quiney 
      [left] => 17 
      [right] => 18 
     ) 

    [11] => Array 
     (
      [value] => Richard Quiney 
      [left] => 19 
      [right] => 20 
     ) 

    [12] => Array 
     (
      [value] => Thomas Quiney 
      [left] => 21 
      [right] => 22 
     ) 

    [13] => Array 
     (
      [value] => Gilbert 
      [left] => 25 
      [right] => 26 
     ) 

    [14] => Array 
     (
      [value] => Joan 
      [left] => 27 
      [right] => 36 
     ) 

    [15] => Array 
     (
      [value] => William Hart 
      [left] => 28 
      [right] => 29 
     ) 

    [16] => Array 
     (
      [value] => Mary Hart 
      [left] => 30 
      [right] => 31 
     ) 

    [17] => Array 
     (
      [value] => Thomas Hart 
      [left] => 32 
      [right] => 33 
     ) 

    [18] => Array 
     (
      [value] => Micheal Hart 
      [left] => 34 
      [right] => 35 
     ) 

    [19] => Array 
     (
      [value] => Anne 
      [left] => 37 
      [right] => 38 
     ) 

    [20] => Array 
     (
      [value] => Richard 
      [left] => 39 
      [right] => 40 
     ) 

    [21] => Array 
     (
      [value] => Edmond 
      [left] => 41 
      [right] => 42 
     ) 

    [22] => Array 
     (
      [value] => John 
      [left] => 44 
      [right] => 45 
     ) 

) 

所以這個問題想起來,如何最好地做到這一點?

我的解決辦法是:

$container = array(); 

function children($item){ 
    $children = 0; 
    foreach($item as $node) 
    if(is_array($node)) 
     $children += children($node)+1; 
    return $children; 
} 

function calculate($item, &$container, $data = array(0,0)){ 
    //althought this one is actually of no use, it could be useful as it contains a count 
    $data[0]++; //$left 

    $right = ($data[0]+(children($item)*2))+1; 

    //store the values in the passed container 
    $container[] = array(
    'value' => $item['value'], 
    'left' => $data[0], 
    'right' => $right, 
); 

    //continue looping 
    $level = $data[1]++; 
    foreach($item as &$node) 
    if(is_array($node)) 
     $data = calculate($node, $container, $data); 

    $data[1] = $level; 
    $data[0]++; 
    return $data; 
} 

calculate($tree, $container); 

其效率如何,我不知道。

但現在進入查詢。

選擇節點的所有後代,我們可以使用

SELECT child.value AS 'Descendants of William', COUNT(*) AS `Level` 
FROM tester AS parent 
JOIN tester AS child ON child.`left` BETWEEN parent.`left` AND parent.`right` 
WHERE parent.`left` > 7 AND parent.`right` < 24 
GROUP BY child.value ORDER BY `level`; 

選擇節點的所有後代,到特定的深度,我們可以使用
注意,我們選擇威廉的後裔的深度的2
威廉姆斯左:7,威廉姆斯右:24,電平:2

SELECT child.value AS 'Descendants of William', COUNT(*) AS `Level` 
FROM tester AS parent 
JOIN tester AS child ON child.`left` BETWEEN parent.`left` AND parent.`right` 
WHERE parent.`left` > 7 AND parent.`right` < 24 
GROUP BY child.value HAVING `level` <= 2 ORDER BY `level`; 

所以這很簡單。

但現在我想知道一些事情,
注意的是,在實際的數據庫,以及左/右的所有行都有一個唯一的ID,幷包含其inviteers ID的「父母」一欄,則返回null沒有邀請

  • 可以說,我想插入David作爲Judith一個孩子,我該怎麼辦呢?
  • 可以說我想要得到Mary Hart's父母和父母父母(array('Henery', 'Joan', 'Mary Hart')),我該怎麼做?
  • 可以說我想從Joan刪除William Hart我該怎麼做?
+0

你試過了什麼?我討厭問,但嵌套很複雜,你的問題聽起來像是你的工作羣衆採購。另外,你甚至還沒有開始撇清這個問題的難度。如:「如果我想顛倒大衛和朱迪思,那麼朱迪思現在就把大衛的地方當作孩子,反之亦然,我怎麼做到這一點[沒有重新索引樹兩次]?」 – 2011-06-09 22:18:06

回答

1

要更新/刪除,您需要增加/減少分支的所有元素的left/right值。
查詢的例子,你可以找到here

效率是多少我不知道。

嵌套集工作非常緩慢與大樹上更新/插入/刪除。而且選擇速度非常快。
因此,只能將此模型與靜態數據一起使用,這些數據將在大多數時間保存不變,並且此樹不會包含數千個節點(或者任何更新都需要數分鐘才能完成)。物化路徑的運行速度更快。

+0

所以,如果我正在處理一個用戶表,那麼數據會被經常插入,最終會有成千上萬的行,但它不會經常更新/刪除,而是會在幾乎每個頁面上讀取(樹結構是我們網站的中心部分),我應該去嵌套集? – Hailwood 2011-06-09 22:30:53

+0

@OZ實際上不僅包含分支的元素,而且包含所有具有left_id> current_element.right_id的元素。 – malko 2011-06-09 22:30:56

+0

@OZ_:我不喜歡你,因爲這不適用於MySQL。 PostGreSql也許是這樣,Celco也在這裏。 – Bytemain 2011-06-09 22:31:18

0

如果您爲每個關係使用DFS,然後使用函數calculate(),則可以非常容易地解決所有問題,如果希望它更詳細。

+0

對不起,什麼是DFS? – Hailwood 2011-06-09 23:14:07

+0

Hailwood:深度優先搜索。 – Bytemain 2011-06-09 23:29:24

1
  • 得到你需要的節點一個節點的父母left_id < child.left_id和right_id> child.right_id,如果你只是想直接祖先可供選擇前一組最高left_id之一。

  • 要刪除一個節點,請將其刪除,然後再降低兩次所有大於已刪除元素右側ID的左側/右側ID。如果(leftId> deleted.leftId)leftId- = 2相同,則爲rightId

  • 插入一個節點爲其創建一些空間爲其添加+ 2與所有節點,leftId> parent.rightId,然後parent.rightId + = 2,然後插入節點with leftId = parent.rightId-2和rightId = parent.rightId-1