超贊,老外的一種避免遞歸查詢所有子部門的樹數(shù)據(jù)表設(shè)計(jì)與實(shí)現(xiàn)!
點(diǎn)擊下方“IT牧場”,選擇“設(shè)為星標(biāo)”

問題來了
查出所有子孫部門
查詢子孫部門總數(shù)
判斷是否葉子節(jié)點(diǎn)
要不試試這個方法?
查出所有子孫部門
查詢子孫部門總數(shù)
判斷是否葉子節(jié)點(diǎn)
其他基本操作
完結(jié)


id??????????部門編號
name????????部門名稱
level???????所在樹層級
parent_id???上級部門編號
| 問題來了
例如:PM加了以下需求:
查出指定部門下所有子孫部門 查詢子孫部門總數(shù) 判斷節(jié)點(diǎn)是否葉子節(jié)點(diǎn)
查出所有子孫部門
查詢子孫部門總數(shù)
判斷是否葉子節(jié)點(diǎn)
| 要不試試這個方法?



查出所有子孫部門
SET?@lft?:=?9;
SET?@rgt?:=?18;
SELECT?*?FROM?department?WHERE?lft?BETWEEN?@lft?AND?@rgt?ORDER?BY?lft?ASC;
/*例子中用BETWEEN將被查部門本身也查了出來。實(shí)際中可以用大于小于*/完美~
查詢子孫部門總數(shù)
行政總監(jiān)的子孫部門數(shù)?=?(18?-?9?-?1)?/?2?=?4
董事長的子孫部門數(shù)?=?(20?-?1?-?1)?/?2?=?9
會計(jì)的子部門數(shù)?=??(14?-?13?-?1)?/?2?=?0
可以數(shù)數(shù)看,確實(shí)沒錯哦~
判斷是否葉子節(jié)點(diǎn)
| 其他基本操作
新增部門

SET?@lft?:=?7;/*新部門的左值*/
SET?@rgt?:=?8;/*新部門的左值*/
SET?@level?:=?5;/*新部門的層級*/
begin;
/*將插入的后續(xù)邊緣的節(jié)點(diǎn)左右數(shù)+2*/
UPDATE?department?SET?lft=lft+2?WHERE?lft?>?@lft;
UPDATE?department?SET?rgt=rgt+2?WHERE?rgt?>=?@lft;
/*插入數(shù)據(jù)*/
INSERT?INTO?department(name,lft,rgt,level)?VALUES('新部門',@lft,@rgt,level);
/*新增影響行數(shù)為0時,必須回滾*/
commit;
/*rollback;*/
刪除部門

SET?@lft?:=?7;/*要刪除的節(jié)點(diǎn)左值*/
SET?@rgt?:=?8;/*要刪除的節(jié)點(diǎn)右值*/
begin;
UPDATE?department?SET?lft=lft-2?WHERE?lft?>?@lft;
UPDATE?department?SET?rgt=rgt-2?WHERE?rgt?>?@lft;
/*刪除節(jié)點(diǎn)*/
DELETE?FROM?department?WHERE?lft=@lft?AND?rgt=@rgt;
/*刪除影響行數(shù)為0時,必須回滾*/
commit;
/*rollback*/
查詢直接子部門

SET?@level?:=?2;/*總經(jīng)理的level*/
SET?@lft?:=?2;/*總經(jīng)理的左值*/
SET?@rgt?:=?19;/*總經(jīng)理的右值*/
SELECT?*?FROM?department?WHERE?lft?>?@lft?AND?rgt?@rgt?AND?level?=?@level+1;
查詢祖鏈路徑
SET?@lft?:=?3;/*產(chǎn)品部左值*/
SET?@rgt?:=?8;/*產(chǎn)品部右值*/
SELECT?*?FROM?department?WHERE?lft?@lft?AND?rgt?>?@rgt?ORDER?BY?lft?ASC;
樹形數(shù)據(jù)展示(JS示例)
let?list?=?[//模擬sql查出來的列表。
????{id:1,name:'root',lft:1,rgt:8,level:1},
????{id:2,name:'child',lft:2,rgt:7,level:2},
????{id:3,name:'grandson',lft:3,rgt:4,level:3},
????{id:4,name:'grandson2',lft:5,rgt:6,level:3}
];
let?rights?=?[]?/*類似于一個棧結(jié)構(gòu)(后進(jìn)先出)*/
let?mp?=?{}
//list.sort((a,b)?=> a.lft - b.lft)//如果你在sql中沒有進(jìn)行排序,需要在這里給他排序。
list.forEach(item?=>?{
????if(rights.length?>?0)?{
????????while(rights[rights.length-1]?????????????rights.splice(-1,?1)//從rights末尾去除
????????}
????}
????let?_level?=?rights.length;
????item._level?=?_level;
????mp[_level]?=?item.id
????item.parent_id?=?_level?-?1?in?mp???mp[_level?-?1]?:?null;//計(jì)算出上級部門編號
????item.is_leaf?=?item.lft?===?item.rgt?-?1;//判斷是否葉子部門
????rights.push(item.rgt)
})
/*上級部門計(jì)算出來了,和存parent_id的效果就一樣了,后面只需要遞歸即可*/
/*遞歸函數(shù)?示例*/
let?recursive?=?(_list,?parent_id?=?null)?=>?{
????let?_tree?=?[];
????_list.forEach(item?=>?{
????????if(item.parent_id?==?parent_id)?{
????????????let?childs?=?recursive(_list,?item.id)
????????????_tree.push({
????????????????...item,
????????????????children:?childs.length?>?0???childs?:?(item.isLeaf???null?:?[])
????????????})
????????}
????})
????return?_tree
}
console.log(recursive(list))
| 完結(jié)
歡迎指正、交流和評論,一起探討更多解決方案 ...
干貨分享
最近將個人學(xué)習(xí)筆記整理成冊,使用PDF分享。關(guān)注我,回復(fù)如下代碼,即可獲得百度盤地址,無套路領(lǐng)??!
?001:《Java并發(fā)與高并發(fā)解決方案》學(xué)習(xí)筆記;?002:《深入JVM內(nèi)核——原理、診斷與優(yōu)化》學(xué)習(xí)筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領(lǐng)域驅(qū)動設(shè)計(jì)速成)》?007:全部?008:加技術(shù)群討論
加個關(guān)注不迷路
喜歡就點(diǎn)個"在看"唄^_^
評論
圖片
表情
