oracle 層次查詢

原文連接

 

 

   

 

 

          1 定義


          層次查詢使用樹的遍歷,走遍含樹形結構的數據集合,來獲取樹的層次關係報表的方法
          樹形結構的父子關係,你可以控制:
          ① 遍歷樹的方向,是自上而下,還是自下而上
          ②  確定層次的開始點(root)的位置
          層次查詢語句正是從這兩個方面來確定的,start with確定開始點,connect by確定遍歷的方向

 

          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後面可以使用子查詢或者任何合法的條件表達式
          例子:

  1. select level,id,manager_id,last_name,title from s_emp
  2. start with title=(select title from s_emp where manager_id is null)
  3. connect by prior id=manager_id;


 

          ㈡ Connect by子句
          Connect by與prior確定一個層次查詢的條件和遍歷的方向(prior確定)
          Connect by prior column_1=column_2;
          其中prior表示前一個節點的意思,可以在connect by等號的前後,列之前,也可以放到select中的列之前
          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.
                        例子:

  1. select level,employee_id,manager_id,last_name,job_id from s_emp
  2. start with manager_id=100
  3. connect by employee_id=prior manager_id;


                         2. )自底向上遍歷
                         先由最底層的子節點,遍歷一直找到根節點。與上面的相反。Connect by之後不能有子查詢,但是可以加其他條件,比如加上and id !=2等。這句話則會截斷樹枝,如果id=2的這個節點下面有很多子孫後代,則全部截斷不顯示。
                         例子:

  1. select level,employee_id,manager_id,last_name,job_id from s_emp
  2. start with manager_id=100
  3. connect by prior employee_id=manager_id and employee_id<>120;


 

          4 使用level和lpad格式化報表:
          Level是層次查詢的一個僞列,如果有level,必須有connect by,start with可以沒有
          Lpad是在一個string的左邊添加一定長度的字符,並且滿足中間的參數長度要求,不滿足自動添加
          例子:

  1. select level,employee_id,manager_id,lpad(last_name,length(last_name)+(level*4)-4,'_'),job_id from s_emp
  2. start with manager_id=100
  3. connect by prior employee_id=manager_id and employee_id<>120


 

          5 修剪branches
          where子句會將節點刪除,但是其後代不會受到影響,connect by 中加上條件會將滿足條件的整個樹枝包括後代都刪除。要注意,如果是connect by之後加條件正好條件選到根,那麼結果和沒有加一樣

 

          6 實際應用

          1)查詢每個等級上節點的數目

  1. 先查看總共有幾個等級:
  2. select count(distinct level)
  3. from s_emp
  4. start with manager_id is null
  5. connect by prior employee_id=manager_id
  6. 要查看每個等級上有多少個節點,只要按等級分組,並統計節點的數目即可,可以這樣寫:
  7. select level,count(last_name)
  8. from s_emp
  9. start with manager_id is null
  10. connect by prior employee_id=manager_id
  11. group by level


 

          2)查看等級關係
          比如給定一個具體的員工看是否對某個員工有管理權

  1. select level,a.* from
  2. s_emp a
  3. where first_name='Douglas' --被管理的節點
  4. start with manager_id is null --開始節點,即:根節點
  5. connect by prior employee_id=manager_id


 

           3)刪除子樹
           比如有這樣的需求,現在要裁員,將某個部門的員工包括經理全部裁掉
           將id爲2的員工管理的所有員工包括自己刪除

  1. delete from s_emp where employee_id in(
  2. select employee_id from
  3. s_emp a
  4. start with employee_id=2 --從id=2的員工開始查找其子節點,把整棵樹刪除
  5. connect by prior employee_id=manager_id)


 

           4)找出每個部門的經理

  1. select level,a.* from
  2. s_emp a
  3. start with manager_id is null
  4. connect by prior employee_id=manager_id and department_id !=prior department_id;--當前行的dept_id不等於前一行的dept_id,即每個子樹中選最高等級節點


 

           5)查詢一個組織中最高的幾個等級

  1. select level,a.* from
  2. s_emp a
  3. where level <=2 –查找前兩個等級
  4. start with manager_id is null
  5. connect by prior employee_id=manager_id and department_id !=prior department_id;


 

       6)合計層次
          有兩個需求,一是對一個指定的子樹subtree做累加計算salary,一是將每行都作爲root節點,然後對屬於這個節點的所有子節點累加計算salary。

  1. 第一種很簡單,求下sum就可以了,語句:
  2. select sum(salary) from
  3. s_emp a
  4. start with id=2—比如從id=2開始
  5. connect by prior id=manager_id;
  6. 第2個需求,需要用到第1個,對每個root節點求這個樹的累加值,然後內部層次查詢的開始節點從外層查詢獲得。
  7. select last_name,salary,(
  8. select sum(salary) from
  9. s_emp
  10. start with id=a.id –讓每個節點都成爲root
  11. connect by prior id=manager_id) sumsalary
  12. from s_emp a;


 

           7)找出指定層次中的葉子節點
           Leaf(葉子)就是沒有子孫的孤立節點。Oracle 10g提供了一個簡單的connect_by_isleaf=1,0表示非葉子節點

  1. select level,id,manager_id,last_name, title from s_emp
  2. where connect_by_isleaf=1 –表示查詢葉子節點
  3. start with manager_id=2
  4. connect by prior id=manager_id;


 

          7 10g新特性


          ① 使用SIBLINGS關鍵字排序
             如果使用order by排序會破壞層次,在oracle10g中,增加了siblings關鍵字的排序
             語法:order  siblings  by <expre>
             它會保護層次,並且在每個等級中按expre排序
             例子:

  1. select level,
  2. employee_id,last_name,manager_id
  3. from s_emp
  4. start with manager_id is null
  5. connect by prior employee_id=manager_id
  6. order siblings by last_name;


          ② CONNECT_BY_ROOT
              Oracle10g新增connect_by_root,用在列名之前表示此行的根節點的相同列名的值

              例子:

  1. select connect_by_root last_name root_last_name, connect_by_root employee_id root_id,
  2. employee_id,last_name,manager_id
  3. from s_emp
  4. start with manager_id is null
  5. connect by prior employee_id=manager_id


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章