Start With (樹查詢)
問題描述:
在數據庫中, 有一種比較常見得 設計模式, 層級結構 設計模式, 具體到 Oracle table中, 字段特點如下:
ID, DSC, PID;
三個字段, 分別表示 當前標識的 ID(主鍵), DSC 當前標識的描述, PID 其父級ID, 比較典型的例子 是 國家, 省, 市 這種層級結構;
省份歸屬於國家, 因此 PID 為 國家的 ID, 以此類推;
create table DEMO ( ID varchar2(10) primary key, DSC varchar2(100), PID varchar2(10) ) --插入幾條數據 Insert Into DEMO values ('00001', '中國', '-1'); Insert Into DEMO values ('00011', '陝西', '00001'); Insert Into DEMO values ('00012', '貴州', '00001'); Insert Into DEMO values ('00013', '河南', '00001'); Insert Into DEMO values ('00111', '西安', '00011'); Insert Into DEMO values ('00112', '咸陽', '00011'); Insert Into DEMO values ('00113', '延安', '00011');
這樣子就成了一個簡單的樹級結構, 我一般將 根節點的 PID 定為 -1;
Start With:
基本語法如下:
SELECT ... FROM + 表名 WHERE + 條件3 START WITH + 條件1 CONNECT BY PRIOR + 條件2 --示例 Select * From DEMO Start With ID = '00001' Connect By Prior ID = PID
條件1: 表示從哪個節點開始查找, 也就是通過條件1 查詢到的數據, 作為后續查詢的起始節點(參數).
當然可以放寬限定條件,如 ID in ('00001', '00011')以取得多個根節點,也就是多棵樹;在連接關系中,除了可以使用列明外,還允許使用列表達式。
如果省略Start With
就默認把所有滿足查詢條件的Tree整個表中的數據從頭到尾遍歷一次,每一個數據做一次根,然后遍歷樹中其他節點信息.
條件2: 是連接條件,其中用PRIOR表示上一條記錄,例如CONNECT BY PRIOR ID = PID,意思就是上一條記錄的ID是本條記錄的PID,即本記錄的父親是上一條記錄。CONNECT BY子句說明每行數據將是按照層次順序檢索,並規定將表中的數據連入樹形結構的關系中。
Prior 在父節點的一側表示, 自底向上查, 在 子節點的一側表示 自上向下查詢;
條件3: 不能用在 Connect By 后, 這里的條件判斷, 等價於 在最后查詢出結果列表之后, 再進行條件篩選; 並非 刪除掉 節點及子節點;
--自底向上 Select * From DEMO Start With ID = '00113' Connect By Prior PID = ID --結果 00113 延安 00011 00011 陝西 00001 00001 中國 -1 --自上向下 Select * From DEMO Start With ID = '00001' --用 Start Wiht PID = '-1' 結果不變 Connect By Prior ID = PID --結果 00001 中國 -1 00011 陝西 00001 00111 西安 00011 00112 咸陽 00011 00113 延安 00011 00012 貴州 00001 00013 河南 00001 --Where 刪除 Select ID, PID, DSC From DEMO WHERE ID <> '00011' Start With ID = '00001' Connect By Prior ID = PID --結果 00001 -1 中國 00111 00011 西安 00112 00011 咸陽 00113 00011 延安 00012 00001 貴州 00013 00001 河南
下面是幾條關鍵字特殊點:
nocycle關鍵字, 有時候數據本身 不合理會導致出現循環的問題, 如 將上述的 ID '00001' 記錄的 'PID' 也改為 '00001', 會出現循環的問題, 這是, 需要用到 nocycle 即可消除循環;
Connect By nocycle Prior ID = PID 即可.
connect_by_isleaf 表示當前節點是否是葉子節點
level 表示當前節點所處層級, 這里的層級指的是 從 start with 查詢到的節點開始往下算起, 當前屬於第幾層級
Select ID, PID, DSC, connect_by_isleaf isLeaf, LEVEL From DEMO Connect By nocycle Prior ID = PID Start With ID = '00001'; --結果 ID PID DSC isLeaf LEVEL 00001 00001 中國 0 0 00011 00001 陝西 0 1 00111 00011 西安 1 2 00112 00011 咸陽 1 2 00113 00011 延安 1 2 00012 00001 貴州 1 1 00013 00001 河南 1 1
這里需要注意的一個點, 如果采用的是 自底向上的 方式查詢, 則 LEVEL 的 層級 同樣是 從底向上, 如 00113 LEVEL 1 00011 LEVEL 2 00001 LEVEL 3.
另外一點: 如果在查詢語句中 Select ID, PID, DSC, connect_by_isleaf isLeaf, LEVEL - 1 LEVEL 這種查詢方式的話, 在 WHERE 判斷條件中, 只需要判斷 LEVEL = 1, 就可以取出 當前查詢節點的 子節點(由於LEVEL 也是 偽列, 需要用子查詢的方式);
SIBLINGS關鍵字:它會保護層次,並且在每個等級中按expre排序。
Select ID, PID, DSC, connect_by_isleaf, LEVEL From DEMO Start With ID = '00001' Connect By nocycle Prior ID = PID ORDER By DSC --結果, 僅貼出部分數據(層級結構被破壞了) 00012 00001 貴州 1 2 00013 00001 河南 1 2 00011 00001 陝西 0 2 00111 00011 西安 1 3 00112 00011 咸陽 1 3 00113 00011 延安 1 3 00001 -1 中國 0 1 --ORDER SIBLINGS By DSC Select ID, PID, DSC, connect_by_isleaf, LEVEL From DEMO Start With ID = '00001' Connect By nocycle Prior ID = PID ORDER SIBLINGS By DSC --結果(Level 層級不變) 00001 -1 中國 0 1 00012 00001 貴州 1 2 00013 00001 河南 1 2 00011 00001 陝西 0 2 00111 00011 西安 1 3 00112 00011 咸陽 1 3 00113 00011 延安 1 3
connect_by_iscycle:存在循環,將返回1,否則返回0