Oracle 層次查詢 connect by



 

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的雇員
SELECT * 
  FROM employees 
 WHERE  last_name = 'Mavris' 
 START WITH last_name = 'Kochhar' --Kochhar的所有雇員
CONNECT BY PRIOR employee_id = manager_id; 
 

場景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排序的, 屌屌的~
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM