您好,登錄后才能下訂單哦!
Oracle樹查詢的最重要的就是select...start with... connect by ...prior 語法了。依托于該語法,我們可以將一個表形結構的中以樹的順序列出來。在下面列述了Oracle中樹型查詢的常用查詢方式以及經常使用的與樹查詢相關的Oracle特性函數等,在這里只涉及到一張表中的樹查詢方式而不涉及多表中的關聯等。
列表結構如下:
PID存儲的是父ID,如果是頂級父節點,該PID為0(表中最好別有null記錄,這會引起全文掃描,建議改成0代替)。
我們從最基本的操作,逐步列出樹查詢中常見的操作,所以查詢出來的節點以家族中的輩份作比方。
1. 查找樹中的所有頂級父節點(輩份最長的人)。
假設這個樹是個目錄結構,那么第一個操作總是找出所有的頂級節點,再根據該節點找到其下屬節點。
SELECT * FROM TREEDATA WHERE PID = 0;
這是個引子,沒用到樹型查詢。
2.查找一個節點的直屬子節點(所有兒子)。
如果查找的是直屬子類節點,也是不用用到樹型查詢的。
SELECT * FROM TREEDATA WHERE PID = 1;
這個可以找到ID為1的直屬子類節點。
3.查找一個節點的所有 直屬子節點(所有后代)。
SELECT * FROM TREEDATA START WITH ID = 1 CONNECT BY PID = PRIOR ID;
這個查找的是ID為1的節點下的所有直屬子類節點,包括子輩的和孫子輩的所有直屬節點。
4.查找一個節點的直屬父節點(父親)。
如果查找的是節點的直屬父節點,也是不用用到樹型查詢的。
SELECT b.* FROM TREEDATA a JOIN TREEDATA b ON a.PID = b.ID WHERE a.ID = 1;
這個找到的是ID為1的節點的直屬父節點,要用到同一張表的關聯了。
5.查找一個節點的所有直屬父節點(祖宗)。
SELECT * FROM TREEDATA START WITH ID = 1 CONNECT BY PRIOR PID = ID;
這里查找的就是ID為1的所有直屬父節點,打個比方就是找到一個人的父親、祖父等。但是值得注意的是這個查詢出來的結果的順序是先列出子類節點再列出父類節點,姑且認為是個倒序吧。
上面列出兩個樹型查詢方式,第3條語句和第5條語句,這兩條語句之間的區別在于prior關鍵字的位置不同,所以決定了查詢的方式不同。 當PID= PRIOR ID時,數據庫會根據當前的ID迭代出PID與該ID相同的記錄,所以查詢的結果是迭代出了所有的子類記錄;而PRIOR ID = PID時,數據庫會跟據當前的PID來迭代出與當前的PID相同的ID的記錄,所以查詢出來的結果就是所有的父類結果。
以下是一系列針對樹結構的更深層次的查詢,這里的查詢不一定是最優的查詢方式,或許只是其中的一種實現而已。
6.查詢一個節點的兄弟節點(親兄弟)。
這里查詢的就是與ID為1的節點同屬一個父節點的節點了,就好比親兄弟了。
7.查詢與一個節點同級的節點(族兄弟)。
這里使用兩個技巧,一個是使用了LEVEL來標識每個節點在表中的級別,還有就是使用with語法模擬出了一張帶有級別的臨時表。
8.查詢一個節點的父節點的的兄弟節點(伯父與叔父)。
這里查詢分成以下幾步。首先,將第7個一樣,將全表都使用臨時表加上級別;其次,根據級別來判斷有幾種類型,以上文中舉的例子來說,有三種情況:(1)當前節點為頂級節點,即查詢出來的lev值為1,那么它沒有上級節點,不予考慮。(2)當前節點為2級節點,查詢出來的lev值為2,那么就只要保證lev級別為1的就是其上級節點的兄弟節點。(3)其它情況就是3以及以上級別,那么就要選查詢出來其上級的上級節點(祖父),再來判斷祖父的下級節點都是屬于該節點的上級節點的兄弟節點。 最后,就是使用UNION將查詢出來的結果進行結合起來,形成結果集。
9.查詢一個節點的父節點的同級節點(族叔)。
這個其實跟第7種情況是相同的。
只需要做個級別判斷就成了。
基本上,常見的查詢在里面了,不常見的也有部分了。其中,查詢的內容都是節點的基本信息,都是數據表中的基本字段,但是在樹查詢中還有些特殊需求,是對查詢數據進行了處理的,常見的包括列出樹路徑等。
補充一個概念,對于數據庫來說,根節點并不一定是在數據庫中設計的頂級節點,對于數據庫來說,根節點就是start with開始的地方。
下面列出的是一些與樹相關的特殊需求。
10.名稱要列出名稱全部路徑。
這里常見的有兩種情況,一種是是從頂級列出,直到當前節點的名稱(或者其它屬性);一種是從當前節點列出,直到頂級節點的名稱(或其它屬性)。舉地址為例:國內的習慣是從省開始、到市、到縣、到居委會的,而國外的習慣正好相反。
從頂部開始:
從當前節點開始:
在這里我又不得不放個牢騷了。oracle只提供了一個sys_connect_by_path函數,卻忘了字符串的連接的順序。在上面的例子中,第一個SQL是從根節點開始遍歷,而第二個SQL是直接找到當前節點,從效率上來說已經是千差萬別,更關鍵的是第一個SQL只能選擇一個節點,而第二個SQL卻是遍歷出了一顆樹來。再次PS一下。
sys_connect_by_path函數就是從start with開始的地方開始遍歷,并記下其遍歷到的節點,start with開始的地方被視為根節點,將遍歷到的路徑根據函數中的分隔符,組成一個新的字符串,這個功能還是很強大的。
11.列出當前節點的根節點。
在前面說過,根節點就是start with開始的地方。
connect_by_root函數用來列的前面,記錄的是當前節點的根節點的內容。
12.列出當前節點是否為葉子。
這個比較常見,尤其在動態目錄中,在查出的內容是否還有下級節點時,這個函數是很適用的。
connect_by_isleaf函數用來判斷當前節點是否包含下級節點,如果包含的話,說明不是葉子節點,這里返回0;反之,如果不包含下級節點,這里返回1。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。