c_id, c_parent_id, c_name, ... 這樣的。但是在網站應用系統的業務中,有非常多的查看樹以及其下所有節點的信息的功能。
比如:查看審判動態欄目以及欄目下所有子欄目的文章,對應到法院業務比較常見的應該是法院及其下轄院(但是這種情況被法院國標碼完美解決)。
那麼,按照原有設計應該如何實現呢?就可能需要遞歸的方式獲取到樹上所有的節點,然後根據這些節點進行查詢。
但是,這種方式會隨着樹的深度的增加,增加遞歸的深度。當然,也可以用緩存將整個樹都存起來,進行遍歷。但是這樣真的是最好的麼?
於是引入改進的前序遍歷樹模型(The Nested Set Model)來解決問題。
那麼,什麼是改進的前序遍歷樹模型呢?
原理
首先把樹按照水平方式擺開。從根節點開始(“Food”),然後在左邊寫上1。然後按照樹的順序(從上到下)給“Fruit”的左邊寫上2。這樣,沿着樹的邊界遍歷,然後同時在每個節點的左邊和右邊寫上數字。最後,我們回到了根節點“Food”在右邊寫上18。下面是標上了數字的樹,同時把遍歷的順序用箭頭標出來了。
數據庫
parent | title | lft | rgt |
Food | 1 | 18 | |
Food | Fruit | 2 | 11 |
Fruit | Red | 3 | 6 |
Red | Cherry | 4 | 5 |
Fruit | Yellow | 7 | 10 |
Yellow | Banana | 8 | 9 |
Food | Meat | 12 | 17 |
Meat | Beef | 13 | 14 |
Meat | Pork | 15 | 16 |
附上一些在實際中正在使用的SQL:
返回完整的樹
- SELECT node.name
- FROM nested_category node, nested_category parent
- WHERE node.lft BETWEEN parent.lft AND parent.rgt
- AND parent.name = 'electronics'
- ORDER BY node.lft
返回所有葉子節點
- SELECT name FROM nested_category WHERE rgt = lft + 1;
插入節點
- LOCK TABLE nested_category WRITE;
- SELECT @myRight := lft FROM nested_category WHERE name = 'TELEVISIONS';
- UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight;
- UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;
- INSERT INTO nested_category
- (name, lft, rgt)
- VALUES
- ('GAME CONSOLES', @myRight + 1, @myRight + 2);
- UNLOCK TABLES;
刪除節點
- LOCK TABLE nested_category WRITE;
- SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
- FROM nested_category
- WHERE name = 'GAME CONSOLES';
- DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;
- UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
- UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight;
- UNLOCK TABLES;
以上就是改進的前序遍歷樹模型的常用sql。
目前網站應用系統正在使用這個模型解決業務上的問題,如果你覺得還不錯,也可以考慮使用一下哦~