1、簡介:Oracle層次化查詢是Oracle特有的功能實現,主要用於返回一個數據集,這個數據集存在樹的關系(數據集中存在一個Pid記錄着當前數據集某一條記錄的Id)。
2、層次化查詢主要包含兩個子句,一個start with另一個是connect by。
start with:這個子句一般用於指定層次化查詢的開始節點(也就是樹的最頂級節點),找到最頂級節點,然后按照一定的規則開始查找其剩余的子節點
connect by:這個子句就是上面所說的規則,用於查找剩余子節點的規則
CREATE TABLE MENU ( "ID" NUMBER, "DATA" VARCHAR2(100), "PID" NUMBER ) insert into MENU (id, data, pid)values (7, 'g', 3); insert into MENU (id, data, pid)values (1, 'a', null); insert into MENU (id, data, pid)values (2, 'b', null); insert into MENU (id, data, pid)values (3, 'c', 2); insert into MENU (id, data, pid)values (4, 'd', 2); insert into MENU (id, data, pid)values (5, 'e', 4); insert into MENU (id, data, pid)values (6, 'f', 1);
下面開始執行層次化查詢,從PId為null的節點(該節點為根節點)開始遞歸查找,查找出所有的更節點下的子節點,構建出一個完整的樹
select ID,DATA,nvl(TO_CHAR(PID),'NULL') from menu start with PID is NULL connect by prior ID=pid
代碼解析:
(1)、start with PID is NULL 指定層次化查詢的根節點,
紅框內的兩個節點為根節點,並開始遍歷其余的節點。
(2)、connect by prior ID=pid 當前節點的PID等於上一層節點的ID,如果滿足條件,就加入到樹結果集中
指定遍歷查找子節點的規則-----> 這一過程是遞歸查找,會一層一層找下去,直到不符合這一規則,則查找停止。
3、實現上面結果集的另一種Sql實現
select ID,DATA,nvl(TO_CHAR(PID),'NULL') from menu start with (data='a' or data='b') connect by prior ID=PID
結論:根節點的定義比較靈活,但是(connect by)遍歷子節點的規則,比較固定基本都是判斷父節點和子節點的ID的,如果理解了這句話,層次化查詢,差不多也就理解了!
4、 Oracle SQL 中的層次化查詢會檢測數據中是否存在回環(死循環),如果存在回環,則會拋出 ORA-01436: CONNECT BY loop in user data . 的錯誤。如果在 connect by 后面加上 nocycle 則 產生回環的最后一層的節點會被刪除。
如果數據中出現這種情況,產生了回環,那么在connect by 后面 加nocycle,節能
select ID,DATA,nvl(TO_CHAR(PID),'NULL') from menu start with (data='a' or data='b') connect by nocycle prior ID=PID
just沒有報錯,有點郁悶,並沒有刪除,不知道哪里出了問題,但是至少不抱錯了!!!
5、Oracle 還為層次化查詢提供了一些偽列( Pseudo Column )。
(1)、CONNECT_BY_ISCYCLE 當這一行有一個子節點同時也是它的祖先節點時返回 1 ,否則返回 0 。
(2)、CONNECT_BY_ISLEAF 當這一行是葉節點時返回 1 ,否則返回 0 。偽列 LEVEL 返回這一行在樹中的層次,根為第一層。
(3)、CONNECT_BY_ROOT 查詢操作符可以加在 connect by 之后的某個字段之前,表示獲得這一行的根節點的該字段的值。
6、層次化查詢還支持一個特殊的函數 SYS_CONNECT_BY_PATH , SYS_CONNECT_BY_PATH ( exp , char ),這個函數返回從根節點到這一行計算其中每個exp 表達式的值,並把它們連接成字符串,每個節點之間用 char 字符來分割。下面是一個例子。
這個函數很棒,可以考慮其他的數據庫也實現這個方法,這樣我們處理一個樹結構就很方便了!!!