淺談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);
- 當前節點遍歷子節點(遍歷當前部門下所有子部門包括本身)
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:
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
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過濾所有返回記錄沒有影響的,這個只是一個例外! -
sys_connect_by_path函數求父節點到子節點路徑
簡單介紹下,在oracle中sys_connect_by_path與connect by 一起使用,也就是先要有或建立一棵樹,否則無用還會報錯。它的主要作用體現在path上即路徑,是可以吧一個父節點下的所有節點通過某個字符區分,然后鏈接在一個列中顯示。
sys_connect_by_path(column,clear),其中column是字符型或能自動轉換成字符型的列名,它的主要目的就是將父節點到當前節點的“path”按照指定的模式出現,char可以是單字符也可以是多字符,但不能使用列值中包含的字符,而且這個參數必須是常量,且不允許使用綁定變量,clear不要用逗號。
文字容易讓人疲勞,放圖和代碼吧!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
結果:
結束語
一個坑兩周時間填平,最近終於休息閑了下來,整理整理加深記憶,好記性不如爛筆頭,不要高估自己的記性,許久不用很快就會忘記的,在學習的道路上,希望自己也希望各位路過的同行不要放棄學習,任重而道遠!現在的我很菜,以后我會成為大神!哈哈,意淫一下!
愛人是路,朋友是樹,人生有一條路,一條路上有許多樹,有錢的時候別迷路,缺錢的時候靠靠樹,幸福的時候莫忘路,休息的時候澆澆樹。
開心一樂
驚弓之鳥——說的是去面試的剛畢業大學生,一聽到用人單位提到行業經驗就落荒而逃的事情;
上聯:做 I T 風風雨雨 又一年
下聯:賣電腦 辛辛苦苦 每一天
橫批:從小不學好,長大賣電腦!