淺談oracle樹狀結構層級查詢

      oracle樹狀結構查詢即層次遞歸查詢,是sql語句經常用到的,在實際開發中組織結構實現及其層次化實現功能也是經常遇到的,雖然我是一個java程序開發者,我一直覺得只要精通數據庫那麼對於java開發你就成功了三分之一,本篇中主要介紹start with...connect by prior 、order by 、sys_connect_by_path

  概要:樹狀結構通常由根節點、父節點、子節點和葉節點組成,簡單來說,一張表中存在兩個字段,dept_id,par_dept_id,那麼通過找到每一條記錄的父級id即可形成一個樹狀結構,也就是par_dept_id(子)=dept_id(父),通俗的說就是這條記錄的par_dept_id是另外一條記錄也就是父級的dept_id,其樹狀結構層級查詢的基本語法是:

  SELECT [LEVEL],*

  FEOM table_name 

  START WITH 條件1

  CONNECT BY PRIOR 條件2

  WHERE 條件3

  ORDER BY 排序字段

  說明:LEVEL---僞列,用於表示樹的層次

     條件1---根節點的限定條件,當然也可以放寬權限,以獲得多個根節點,也就是獲取多個樹

     條件2---連接條件,目的就是給出父子之間的關係是什麼,根據這個關係進行遞歸查詢

     條件3---過濾條件,對所有返回的記錄進行過濾。

     排序字段---對所有返回記錄進行排序

  對prior說明:要的時候有兩種寫法:connect by prior dept_id=par_dept_id 或 connect by dept_id=prior par_dept_id,前一種寫法表示採用自上而下的搜索方式(先找父節點然後找子節點),後一種寫法表示採用自下而上的搜索方式(先找葉子節點然後找父節點)。 

  樹狀結構層次化查詢需要對樹結構的每一個節點進行訪問並且不能重複,其訪問步驟爲:

  

  大致意思就是掃描整個樹結構的過程即遍歷樹的過程,其用語言描述就是:

  步驟一:從根節點開始;

  步驟二:訪問該節點;

  步驟三:判斷該節點有無未被訪問的子節點,若有,則轉向它最左側的未被訪問的子節,並執行第二步,否則執行第四步; 

  步驟四:若該節點爲根節點,則訪問完畢,否則執行第五步; 

  步驟五:返回到該節點的父節點,並執行第三步驟。 

  除此之外,sys_connect_by_path函數是和connect  by 一起使用的,在實戰中具體帶目的具體介紹!

  實戰:最近做項目的組織結構,對於部門的各級層次顯示,由於這部分掌握不牢固,用最笨的like模糊查詢解決了,雖然功能實現了,但是問題很多,如擴展性不好,稍微改下需求就要進行大改,不滿意最後對其進行了優化。在開發中能用數據庫解決的就不要用java去解決,這也是我一直保持的想法並堅持着。

  對於建表語句及其測試數據我放在另外一篇博客中,需要進行測試的可以過去拷貝運行測試驗證下!

  博客地址淺談oracle樹狀結構層級查詢測試數據

  在這張表中有三個字段:dept_id 部門主鍵id;dept_name  部門名稱;dept_code 部門編碼;par_dept_id   父級部門id(首級部門爲 -1);

  1. 當前節點遍歷子節點(遍歷當前部門下所有子部門包括本身)
    1
    2
    3
    4
    5
    select t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level
    from SYS_DEPT t
    start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
    connect by prior t.dept_id = t.par_dept_id
    order by level, t.dept_code

    結果:

    dept_id=40288ac45a3c1e8b015a3c28b4ae01d6 是客運部主鍵,對其下的所有子部門進行遍歷,同時用  order by level,dept_code 進行排序 以便達到實際生活中想要的數據;共31條數據,部分數據如圖所示:


    但是:

      有問題啊,如果你想在上面的數據中獲取層級在2也就是level=2的所有部門,發現剛開始的時候介紹的語言不起作用?並且會報ORA-00933:sql命令未正確結束,why?

    這個我暫時也沒有得到研究出理論知識,但是改變下where level='2'的位置發現纔會可以的。錯誤的和正確的sql我們對比一下,以後會用就行,要是路過的大神知道爲什麼,還請告知下,萬分感謝!

    錯誤sql:

    1
    2
    3
    4
    5
    6
    select t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level
    from SYS_DEPT t 
    start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
    connect by prior t.dept_id = t.par_dept_id
    where level '2'
    order by level, t.dept_code
    正確sql:
    1
    2
    3
    4
    5
    6
    select t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level 
    from SYS_DEPT t
    where level '2'
    start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6'
    connect by prior t.dept_id = t.par_dept_id
    order by level, t.dept_code


    當然了,這個對其他形式的where過濾所有返回記錄沒有影響的,這個只是一個例外!

  2. sys_connect_by_path函數求父節點到子節點路徑
    簡單介紹下,在oracle中sys_connect_by_path與connect by 一起使用,也就是先要有或建立一棵樹,否則無用還會報錯。它的主要作用體現在path上即路徑,是可以吧一個父節點下的所有節點通過某個字符區分,然後鏈接在一個列中顯示。
    sys_connect_by_path(column,clear),其中column是字符型或能自動轉換成字符型的列名,它的主要目的就是將父節點到當前節點的“path”按照指定的模式出現,char可以是單字符也可以是多字符,但不能使用列值中包含的字符,而且這個參數必須是常量,且不允許使用綁定變量,clear不要用逗號
    文字容易讓人疲勞,放圖和代碼吧!

    1
    2
    3
    4
    5
    select sys_connect_by_path(t.dept_name,'-->'),t.dept_id, t.dept_name, t.dept_code, t.par_dept_id, level 
    from SYS_DEPT t  
    start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6' 
    connect by prior t.dept_id = t.par_dept_id
    order by level, t.dept_code

    結果:

     

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