oracle 層次查詢
語法:
SELECT ... FROM
[WHERE condition] --過濾某些節點
[ START WITH [nocycle] start_condition] --定義查詢的起點, 可以使用子查詢
CONNECT BY [[nocycle] PRIOR COLUMN1 = COLUMN2 [AND ...]]; --定義父子關系
order [ sibilings ] by ...
例1:
找出101雇員, 及其全下屬/上司
select * from myemp start with employee_id = 101 connect by prior employee_id = manager_id; -- 找下屬 -- connect by employee_id = prior manager_id; --找上司
prior在等號哪邊,表示哪邊是"我的"
找下屬: "我的"employee_id = "別人的"manager_id --> 找出我的下屬 (向下查詢)
找上司: employee_id = prior manager_id 別人的工號 = 我的經理編號 --> 別人是我的經理 & 別人是我經理的經理 --> 我的上司們
注意,level偽列只能和connect by子句結合使用,
否則Oracle會返回錯誤 ORA-01788: 此查詢塊中要求 CONNECT BY 子句
例2:
統計樹形的層數
SELECT COUNT(DISTINCT LEVEL) FROM EMPLOYEES START WITH MANAGER_ID IS NULL CONNECT BY PRIOR EMPLOYEE_ID = MANAGER_ID;
例3:
統計樹的節點數量 , 例如, 查詢每個級別的雇員數量
select count(level) --在統計樹種節點的數量時, 一定不能加distinct! from employees start with manager_id is null connect by prior employee_id = manager_id group by level;
例4:
刪除子樹
delete from myemp where employee_id in ( select employee_id from myemp start with last_name = 'Kochhar' connect by prior employee_id = manager_id);
過濾某些結果集
場景1:使用 where 過濾某些節點 , 注意不是過濾分支!
例1:
查看level=2的所有雇員的信息
select level, employee_id, last_name, manager_id from employees where level = 2 --注意where子句出現的位置 start with manager_id is null connect by prior employee_id = manager_id;
注意:where子句比connect by后執行。
即先用connect by生成一顆樹, 然后再用where來砍樹, 並不是where在前面就先執行它
例2:
查詢Mavris是不是Kochhar的雇員
場景2: 使用 connect by ... and ... 過濾某些分支
例1 查詢Raphaely及其的所有下屬
select * from employees start with last_name = 'Raphaely' connect by prior employee_id = manager_id;
例2 查詢除了Raphaely和他下屬的所有員工
select * from employees start with manager_id is null connect by prior employee_id = manager_id and last_name <> 'Raphaely';
格式化查詢 lpad('-', 3 * (level - 1), '-')
例:使用三個橫杠作為縮進格式化查詢
select * from employees start with manager_id is null connect by prior employee_id = manager_id and last_name <> 'Raphaely';
SYS_CONNECT_BY_PATH() 函數 ☆
作用:
將父節點到當前節點的路徑按照指定的模式展現出來
格式:
sys_connect_by_path(<列明>,<連接串>)
CONNECT_BY_ISLEAF 偽列
作用:
判斷層次查詢結果集中的行是不是葉子節點
返回值:
0表示不是葉子節點,
1表示是葉子節點
例:

CONNECT_BY_ROOT 字段x -> 找到該節點最頂端節點的字段x
用在列名之前,找出此行的根節點行的相同列名的值
不是一直找到"根", 而是一直找到當前便利的分支的
select last_name "Employee", connect_by_root last_name "Manager", sys_connect_by_path(last_name, ' -> ') "Path" from hr.employees where level > 1 -- start with 加不加?? connect by prior employee_id = manager_id order by last_name, length("Path");


思考? 為什么不能加 start with ? 加了會有什么效果?
不加start with , 則每個節點都遍歷一次 , connect_by_root 找到頂端的經理人會不同
而加了start with manager_id is null 則從樹的根節點 King 開始遍歷, 從而connect_by_root每個人的頂端的經理都是King
10g新特性 采用sibilings排序
作用:
因為使用order by排序會破壞層次,所以在oracle10g中,增加了siblings關鍵字的排序給葉子節點的關鍵字排序
語法:
order siblings by <expre> asc|desc ;
它會保護層次,並且在每個等級中按expre排序
注意:
order siblings by 必須緊跟着connect by
所以不能再用order by 了
例子:
select t.employee_id,t.manager_id,t.first_name,t.salary,sys_connect_by_path(t.first_name, '->'),level from hr.employees t start with manager_id is null connect by prior employee_id = manager_id order by salary desc;

最后的結果是嚴格按照salary排序的,這樣把層級關系都打亂了
采用sibilings排序:
select t.employee_id, t.manager_id, t.first_name, t.salary, sys_connect_by_path(t.first_name, '->'), level from hr.employees t start with manager_id is null connect by prior employee_id = manager_id order siblings by salary desc;

結果的樹結構沒有被打亂,且沒層級的sibilings都是按照salary排序的, 屌屌的~