1 定義:
層次查詢使用樹的遍歷,走遍含樹形結構的數據集合,來獲取樹的層次關係報表的方法
樹形結構的父子關係,你能夠控制:
① 遍歷樹的方向,是自上而下,仍是自下而上
② 肯定層次的開始點(root)的位置
層次查詢語句正是從這兩個方面來肯定的,start with肯定開始點,connect by肯定遍歷的方向 www.2cto.com
2 語法:
註釋:
① level是僞列,表示等級
② from後面只能是一個表或視圖,對於from是視圖的,那麼這個view不能包含join
③ Where條件限制了查詢返回的行,可是不影響層次關係,屬於將節點截斷,可是這個被截斷的節點的下層child不受影響
④ prior是個形容詞,可放在任何地方
⑤ 完全剪枝條件應放在connect by;單點剪掉條件應放在where子句。可是,connect by的優先級要高於where,也就是sql引擎先執行connect by
⑥ 在start with中表達式能夠有子查詢,可是connect by中不能有子查詢
3 遍歷樹:
㈠ Start with子句
Start with肯定將哪行做爲root,若是沒有start with,則每行都看成root,而後查找其後代,這不是一個真實的查詢。Start with後面可使用子查詢或者任何合法的條件表達式
例子:
[sql]
select level,id,manager_id,last_name,title from s_emp
start with title=(select title from s_emp where manager_id is null)
connect by prior id=manager_id;
㈡ Connect by子句
Connect by與prior肯定一個層次查詢的條件和遍歷的方向(prior肯定)
Connect by prior column_1=column_2;
其中prior表示前一個節點的意思,能夠在connect by等號的先後,列以前,也能夠放到select中的列以前 www.2cto.com
Connect by也能夠帶多個條件,好比 connect by prior id=manager_id and id>10
1. )自頂向下遍歷:
先由根節點,而後遍歷子節點。column_1表示父key,column_2表示子key。即這種狀況下:connect by prior 父key=子key表示自頂向下,等同於connect by 子key=prior 父key.
例子:
[sql]
select level,employee_id,manager_id,last_name,job_id from s_emp
start with manager_id=100
connect by employee_id=prior manager_id;
2. )自底向上遍歷:
先由最底層的子節點,遍歷一直找到根節點。與上面的相反。Connect by以後不能有子查詢,可是能夠加其餘條件,好比加上and id !=2等。這句話則會截斷樹枝,若是id=2的這個節點下面有不少子孫後代,則所有截斷不顯示。
例子:
[sql]
select level,employee_id,manager_id,last_name,job_id from s_emp
start with manager_id=100 www.2cto.com
connect by prior employee_id=manager_id and employee_id<>120;
4 使用level和lpad格式化報表:
Level是層次查詢的一個僞列,若是有level,必須有connect by,start with能夠沒有
Lpad是在一個string的左邊添加必定長度的字符,而且知足中間的參數長度要求,不知足自動添加
例子:
[sql]
select level,employee_id,manager_id,lpad(last_name,length(last_name)+(level*4)-4,'_'),job_id from s_emp
start with manager_id=100
connect by prior employee_id=manager_id and employee_id<>120
5 修剪branches:
where子句會將節點刪除,可是其後代不會受到影響,connect by 中加上條件會將知足條件的整個樹枝包括後代都刪除。要注意,若是是connect by以後加條件正好條件選到根,那麼結果和沒有加同樣
6 實際應用
1)查詢每一個等級上節點的數目
[sql]
先查看總共有幾個等級:
select count(distinct level)
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id
要查看每一個等級上有多少個節點,只要按等級分組,並統計節點的數目便可,能夠這樣寫:
select level,count(last_name)
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id
group by level www.2cto.com
2)查看等級關係
好比給定一個具體的員工看是否對某個員工有管理權
[sql]
select level,a.* from
s_emp a
where first_name='Douglas' --被管理的節點
start with manager_id is null --開始節點,即:根節點
connect by prior employee_id=manager_id
3)刪除子樹
好比有這樣的需求,如今要裁人,將某個部門的員工包括經理所有裁掉
將id爲2的員工管理的全部員工包括本身刪除
[sql]
delete from s_emp where employee_id in(
elect employee_id from
s_emp a
start with employee_id=2 --從id=2的員工開始查找其子節點,把整棵樹刪除
connect by prior employee_id=manager_id)
4)找出每一個部門的經理
[sql]
select level,a.* from
s_emp a www.2cto.com
start with manager_id is null
connect by prior employee_id=manager_id and department_id !=prior department_id;--當前行的dept_id不等於前一行的dept_id,即每一個子樹中選最高等級節點
5)查詢一個組織中最高的幾個等級
[sql]
select level,a.* from
s_emp a
where level <=2 –查找前兩個等級
start with manager_id is null
connect by prior employee_id=manager_id and department_id !=prior department_id;
6)合計層次
有兩個需求,一是對一個指定的子樹subtree作累加計算salary,一是將每行都做爲root節點,而後對屬於這個節點的全部子節點累加計算salary。
[sql]
第一種很簡單,求下sum就能夠了,語句:
select sum(salary) from
s_emp a
start with id=2—好比從id=2開始
connect by prior id=manager_id;
第2個需求,須要用到第1個,對每一個root節點求這個樹的累加值,而後內部層次查詢的開始節點從外層查詢得到。
select last_name,salary,(
select sum(salary) from
s_emp www.2cto.com
start with id=a.id –讓每一個節點都成爲root
connect by prior id=manager_id) sumsalary
from s_emp a;
7)找出指定層次中的葉子節點
Leaf(葉子)就是沒有子孫的孤立節點。
Oracle 10g提供了一個簡單的connect_by_isleaf=1,0表示非葉子節點
[sql]
select level,id,manager_id,last_name, title from s_emp
where connect_by_isleaf=1 –表示查詢葉子節點
start with manager_id=2
connect by prior id=manager_id;
7 10g新特性:
① 使用SIBLINGS關鍵字排序
若是使用order by排序會破壞層次,在oracle10g中,增長了siblings關鍵字的排序
語法:order siblings by <expre>
它會保護層次,而且在每一個等級中按expre排序
例子:
[sql]
select level, www.2cto.com
employee_id,last_name,manager_id
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id
order siblings by last_name;
② CONNECT_BY_ROOT
Oracle10g新增connect_by_root,用在列名以前表示此行的根節點的相同列名的值
例子:
[sql]
select connect_by_root last_name root_last_name, connect_by_root employee_id root_id,
employee_id,last_name,manager_id
from s_emp
start with manager_id is null
connect by prior employee_id=manager_id