采用左右值編碼的設計方案,在進行類別樹的遍歷時,由于只需進行2次查詢,消除了遞歸,再加上查詢條件都為數字比較,效率極高,類別樹的記錄條目越多,執行效率越高。看到這里,相信不少人對這種設計方案有所心動了,下面讓我們接著看看如何在這種表結構中實現插入、刪除、同層平移節點(變更同層節點排序)的功能。
?
假定我們要在節點“肉類”下添加一個子節點“牛肉”,該樹將變成:
???????????????????????????????????? 1商品18+2
????????????????????? +--------------------------------------------+
??????????????? 2食品11+2????????????????????????????????? 12+2電器17+2
????????? +-----------------+??????????????????????????????????? +-------------------------+
??? 3肉類6+2?? 7+2蔬菜類10+2???????? 13+2電視機14+2??? 15+2電冰箱16+2
??? +-------------+
4豬肉5? 6牛肉7? 8+2白菜9+2
?
看完上圖相應節點左右值的變化后,相信大家都知道該如何寫相應的sql腳本吧?下面我給出相對完整的插入子節點的存儲過程:
CREATE?PROCEDURE?[dbo].[AddSubNodeByNode]
(
???
@type_id?int,
???
@name?varchar(50)
)
AS
declare?@rgt?int
if?exists (select?1?from tree where type_id=@type_id)
???
begin
??????
SET XACT_ABORT ON
??????
BEGIN?TRANSACTION
???????
select?@rgt=rgt from tree where type_id=@type_id
???????
update tree set rgt=rgt+2?where rgt>=@rgt
???????
update tree set lft=lft+2?where lft>=@rgt
???????
insert?into tree (name,lft,rgt) values (@name,@rgt,@rgt+1)???
???????
COMMIT?TRANSACTION
??????
SET XACT_ABORT OFF???
???
end
go
?
然后,我們刪除節點“電視機”,再來看看該樹會變成什么情況:
??????????????????????????????????????????? 1商品20-2
?????????????????????? +-----------------------------------+
??????????????? 2食品13??????????????????????????????? 14電器19-2
????????? +-----------------+???????????????
?????? 3肉類8????????? 9蔬菜類12????????????? 17-2電冰箱18-2
??? +----------+
4豬肉5? 6牛肉7? 10白菜11
?
  相應的存儲過程如下:
CREATE?PROCEDURE?[dbo].[DelNode]?
???
@type_id?int
AS
declare?@lft?int
declare?@rgt?int
if?exists (select?1?from tree where type_id=@type_id)
???
begin
??????
SET XACT_ABORT ON
??????
BEGIN?TRANSACTION
???????
select?@lft=lft,@rgt=rgt from tree where type_id=@type_id
???????
delete?from tree where lft>=@lft?and rgt<=@rgt
???????
update tree set lft=lft-(@rgt-@lft+1) where lft>@lft
???????
update tree set rgt=rgt-(@rgt-@lft+1) where rgt>@rgt
???????
COMMIT?TRANSACTION
??????
SET XACT_ABORT OFF???
End
?
  注意:因為刪除某個節點會同時刪除該節點的所有子孫節點,而這些被刪除的節點的個數為:(被刪節點的右值-被刪節點的左值+1)/2,而任何一個節點同時具有唯一的左值和唯一的右值,故刪除作廢節點后,其他相應節點的左、右值需要調整的幅度應為:減少(被刪節點的右值-被刪節點的左值+1)。
?
? 最后,讓我們看看平移節點“電器”,將其和其所有子孫節點移動到節點“食品”之前后,該樹會變成什么情況:
?
             1商品18
+-----------------------------------+
??????????????? 14-12電器17-12????????????????????? 2+4食品13+4
?????????????????????????????????????????????????????????????? +----------------------+???????????????
???????????? 15-12電冰箱16-12????? 3+4肉類8+4????? 9+4蔬菜類12+4???????
??????????????????????????????????????????????? +-------------------+
????????????????????????????????????? 4+4豬肉5+4???? 6+4牛肉7+4 10+4白菜11+4
?
大家仔細觀察一下交換后同層2個節點和其所有子孫節點左右值的變化,可以發現一個明顯的規律,那就是,節點“電器”及其所有子孫節點的左右值均減少12,而節點“食品”及其所有子孫節點的左右值均增加4。而節點“電器”+其子孫節點的數量為2,節點“食品”+其子孫節點的數量為6,這其中有什么聯系嗎?還記得我在刪除節點的存儲過程后面的注釋嗎?任何一個節點同時具有唯一的左值和唯一的右值。讓我們把節點數量*2,正好和節點左右值需要調整的幅度相等。由此規律,我們可以編寫出類似下面的存儲過程來實現節點同層前移的功能:
CREATE?PROCEDURE?[dbo].[MoveNodeUp]?
???
@type_id?int
AS
declare?@lft?int
declare?@rgt?int
declare?@layer?int
if?exists (select?1?from tree where type_id=@type_id)
???
begin
??????
SET XACT_ABORT ON
??????
BEGIN?TRANSACTION
???????
select?@lft=lft,@rgt=rgt,@layer=layer from TreeView where type_id=@type_id
???????
if?exists (select?*?from TreeView where rgt=@lft-1?and layer=@layer)
??????????
begin
??????????????
declare?@brother_lft?int
??????????????
declare?@brother_rgt?int
??????????????
select?@brother_lft=lft,@brother_rgt=rgt from TreeView where rgt=@lft-1?and layer=@layer
??????????????
update tree set lft=lft-(@brother_rgt-@brother_lft+1) where lft>=@lft?and rgt<=@rgt
??????????????
update tree set lft=lft+(@rgt-@lft+1) where lft>=@brother_lft?and rgt<=@brother_rgt
??????????????
update tree set rgt=rgt-(@brother_rgt-@brother_lft+1) where rgt>@brother_rgt?and rgt<=@rgt
??????????????
update tree set rgt=rgt+(@rgt-@lft+1) where lft>=@brother_lft+(@rgt-@lft+1) and rgt<=@brother_rgt
??????????
end
???????
COMMIT?TRANSACTION
??????
SET XACT_ABORT OFF???
???
end
?
  注意:節點的同層平移可以采用臨時表來做中介,降低代碼的復雜度。不用臨時表來處理也行,但是update語句順序一定要考慮周詳。否則,一旦出現bug,對整個類別表的破壞是驚人的,強烈推薦在做上述工作前對類別表進行完整備份。
?
  同層下移的存儲過程和同層上移類似,有興趣的朋友可以自己動手編寫體味一下其中的細節,我就不在這里列出來了。
?
  最后,我對上面這種左右值編碼實現無限分級類別樹的方案做一個總結:
  優點:在消除遞歸的前提下實現了無限分級,而且查詢條件是基于整形數字比較的,效率很高。可以進行先序列表,添加,修改,刪除,同層平移等常規操作,基本滿足需求。
  缺點:由于這種左右值編碼的方式和常見的阿拉伯數字直觀排序不同,再加上節點在樹中的層次,順序不是直觀顯示出來,而必須通過簡單的公式計算后得到,需要花費一定的時間對其數學模型進行深入理解。而且,采用該方案編寫相關存儲過程,新增,刪除,同層平移節點需要對整個樹進行查詢修改,由此導致的代碼復雜度,耦合度較高,修改維護的風險較高。?

文章來源:http://x-spirit.spaces.live.com/Blog/cns!CC0B04AE126337C0!368.entry