樹形查詢一般用於上下級場合,使用的特殊sql語法包括level,prior,start with,connect by等,下面將就實例來說明其用法。
表定義:
create table tb_hierarchy( id number(4,0) primary key, name nvarchar2(20) not null, pid number(4,0))
充值:
insert into tb_hierarchy(id,name) values('1','Gates'); insert into tb_hierarchy(id,pid,name) values('2','1','Alice'); insert into tb_hierarchy(id,pid,name) values('3','2','Bill'); insert into tb_hierarchy(id,pid,name) values('4','2','Cindy'); insert into tb_hierarchy(id,pid,name) values('5','2','Douglas'); insert into tb_hierarchy(id,pid,name) values('6','1','Eliot'); insert into tb_hierarchy(id,pid,name) values('7','6','Mick'); insert into tb_hierarchy(id,pid,name) values('8','6','Flex'); insert into tb_hierarchy(id,pid,name) values('9','7','張三'); insert into tb_hierarchy(id,pid,name) values('10','7','李四'); insert into tb_hierarchy(id,pid,name) values('11','7','王五');
先讓我們查出員工及其上級:
--列出員工和上級 select level,id,name,(prior name) as mngName from tb_hierarchy start with pid is NULL connect by (prior id)=pid
查詢結果:
SQL> select level,id,name,(prior name) as mngName 2 from tb_hierarchy 3 start with pid is NULL 4 connect by (prior id)=pid; LEVEL ID NAME MNGNAME ---------- ---------- ---------------------------------------- ---------------------------------------- 1 1 Gates 2 2 Alice Gates 3 3 Bill Alice 3 4 Cindy Alice 3 5 Douglas Alice 2 6 Eliot Gates 3 7 Mick Eliot 4 9 張三 Mick 4 10 李四 Mick 4 11 王五 Mick 3 8 Flex Eliot 已選擇11行。
從上面的level一列可以看出,Gates居於公司領導核心,屬於董事長;他下面是alice,處於總經理地位;Alice下面有三個經理,分別是Bill,Cindy,Douglas...
這些結果是怎么查出來的呢?讓我們看看SQL:
select level,id,name,(prior name) as mngName from tb_hierarchy start with pid is NULL connect by (prior id)=pid
解讀:
level:屬於關鍵字,是和rownum一樣的偽列,代表節點在整棵樹中的層級,如Flex處於等級三,他上面有Eliot,Eliot上面有總頭頭Gates。 prior name:prior屬於關鍵字,代表本條記錄的上一條,如本條是(3,8,Flex);那么prior就是(2,6,Eliot);知道了prior是哪一條記錄,我們就知道了prior name是Eliot,prior id就是6。 start with:這個語法告訴樹形查詢應該以pid是空的記錄作為樹的起點。
下面我們來查查以Mick為起點會是什么效果:
SQL> select level,id,name,(prior name) as mngName 2 from tb_hierarchy 3 start with name='Mick' 4 connect by (prior id)=pid; LEVEL ID NAME MNGNAME ---------- ---------- ---------------------------------------- ---------------------------------------- 1 7 Mick 2 9 張三 Mick 2 10 李四 Mick 2 11 王五 Mick
結果查詢出了以Mick為組長,張三李四王五為組員的苦逼外包小組。
在國企干活的人一般稱底下做事的為員,管員的人為基層干部,上下都是干部的為中層干部,上面再沒人的則是首長。
下面我們查查誰是員,誰是基層領導干部,誰是中層領導干部,誰是首長:
SQL> select level,id,name,(prior name) as mngName, 2 decode(level,1,1) as 首長, 3 decode(level,2,1) as 中層干部, 4 decode(level,3,1) as 基層干部, 5 decode(connect_by_isleaf,1,1) as 員工 6 from tb_hierarchy 7 start with pid is NULL 8 connect by (prior id)=pid; LEVEL ID NAME MNGNAME 首長 中層干部 基層干部 員工 ---------- ---------- -------------------- -------------------- ---------- ---------- ---------- ---------- 1 1 Gates 1 2 2 Alice Gates 1 3 3 Bill Alice 1 1 3 4 Cindy Alice 1 1 3 5 Douglas Alice 1 1 2 6 Eliot Gates 1 3 7 Mick Eliot 1 4 9 張三 Mick 1 4 10 李四 Mick 1 4 11 王五 Mick 1 3 8 Flex Eliot 1 1 已選擇11行。
上面的語法中多了一個關鍵字connect_by_isleaf,它表示當前節點下面沒有子節點,或是當前記錄下沒有地位更低的記錄(996!最苦逼的一群人)
下面SQL可以把id前面加點層次:
SQL> select lpad(' ',level,' ')||id AS padid, 2 level,id,name,(prior name) as mngName, 3 decode(level,1,1) as 首長, 4 decode(level,2,1) as 中層干部, 5 decode(level,3,1) as 基層干部, 6 decode(connect_by_isleaf,1,1) as 員工 7 from tb_hierarchy 8 start with pid is NULL 9 connect by (prior id)=pid; PADID LEVEL ID NAME MNGNAME 首長 中層干部 基層干部 員工 ---------- ---------- ---------- ---------- -------------------- ---------- ---------- ---------- ---------- 1 1 1 Gates 1 2 2 2 Alice Gates 1 3 3 3 Bill Alice 1 1 4 3 4 Cindy Alice 1 1 5 3 5 Douglas Alice 1 1 6 2 6 Eliot Gates 1 7 3 7 Mick Eliot 1 9 4 9 張三 Mick 1 10 4 10 李四 Mick 1 11 4 11 王五 Mick 1 8 3 8 Flex Eliot 1 1 已選擇11行。
下面把每個人的上級全列出來:
SQL> col path format a30; SQL> select level,id,name,(prior name) as mngName, 2 sys_connect_by_path(name,',') as path 3 from tb_hierarchy 4 start with pid is NULL 5 connect by (prior id)=pid; LEVEL ID NAME MNGNAME PATH ---------- ---------- ---------- -------------------- ------------------------------ 1 1 Gates ,Gates 2 2 Alice Gates ,Gates,Alice 3 3 Bill Alice ,Gates,Alice,Bill 3 4 Cindy Alice ,Gates,Alice,Cindy 3 5 Douglas Alice ,Gates,Alice,Douglas 2 6 Eliot Gates ,Gates,Eliot 3 7 Mick Eliot ,Gates,Eliot,Mick 4 9 張三 Mick ,Gates,Eliot,Mick,張三 4 10 李四 Mick ,Gates,Eliot,Mick,李四 4 11 王五 Mick ,Gates,Eliot,Mick,王五 3 8 Flex Eliot ,Gates,Eliot,Flex 已選擇11行。
--2020年4月18日--
以上用到的全部SQL:
create table tb_hierarchy( id number(4,0) primary key, name nvarchar2(20) not null, pid number(4,0)) insert into tb_hierarchy(id,name) values('1','Gates'); insert into tb_hierarchy(id,pid,name) values('2','1','Alice'); insert into tb_hierarchy(id,pid,name) values('3','2','Bill'); insert into tb_hierarchy(id,pid,name) values('4','2','Cindy'); insert into tb_hierarchy(id,pid,name) values('5','2','Douglas'); insert into tb_hierarchy(id,pid,name) values('6','1','Eliot'); insert into tb_hierarchy(id,pid,name) values('7','6','Mick'); insert into tb_hierarchy(id,pid,name) values('8','6','Flex'); insert into tb_hierarchy(id,pid,name) values('9','7','張三'); insert into tb_hierarchy(id,pid,name) values('10','7','李四'); insert into tb_hierarchy(id,pid,name) values('11','7','王五'); --列出員工和上級 select level,id,name,(prior name) as mngName from tb_hierarchy start with pid is NULL connect by (prior id)=pid --以mick為起點 select level,id,name,(prior name) as mngName from tb_hierarchy start with name='Mick' connect by (prior id)=pid --列出是員,基層干部,中級干部和首長 select level,id,name,(prior name) as mngName, decode(level,1,1) as 首長, decode(level,2,1) as 中層干部, decode(level,3,1) as 基層干部, decode(connect_by_isleaf,1,1) as 員工 from tb_hierarchy start with pid is NULL connect by (prior id)=pid --加入層次列 select lpad(' ',level,' ')||id AS padid, level,id,name,(prior name) as mngName, decode(level,1,1) as 首長, decode(level,2,1) as 中層干部, decode(level,3,1) as 基層干部, decode(connect_by_isleaf,1,1) as 員工 from tb_hierarchy start with pid is NULL connect by (prior id)=pid --把上級在path里全列出來 select level,id,name,(prior name) as mngName, sys_connect_by_path(name,',') as path from tb_hierarchy start with pid is NULL connect by (prior id)=pid
