一張表,有多顆子樹(根節點為0),現在我想知道每個節點屬於哪個子樹。舉例:鈴音目錄結構下有多個大分類:中外名曲、流行經典、浪漫舞曲……,每個大類下面又有多個子類,子類下面還可以細分。那現在想要知道每個子類分屬哪個大類,或者要統計每個大類下面有多少個子類。
看下面的例子,DIRINDEX分別為1、2、3的就是大分類,其他編號的都是子類或孫子類:
select dirindex, fatherindex, RPAD('' '', 2*(LEVEL-1)) || dirname from t_tonedirlib
start with fatherindex = 0
connect by fatherindex = prior dirindex
DIRINDEX FATHERINDEX DIRNAME
--------------------- ------------------------------------
1 0 中文經典
52 1 kkkkkkk
70 52 222
58 52 sixx
59 52 seven
69 52 uiouoooo
55 52 four
7 1 流行風雲
8 1 影視金曲
1111 8 aaa &
nbsp; 1112 8 bbb
1113 8 ccc
9 1 古典音樂
81 1 小熊之家
104 81 龍珠
105 81 snoppy
101 81 叮當1
102 81 龍貓
103 81 叮當2
2 0 熱門流行
31 2 有獎活動
32 2 相約香格裡拉
50 2 新浪彩鈴
3 0 老歌回放
333 3 老電影
335 3 懷舊金曲
26 rows selected
如何統計1、2、3三個大類下有哪些子類,有多少個子類?在9i及以前要做這樣的統計十分麻煩。現在10G提供了一個新特性:CONNECT_BY_ROOT,他的作用就是使結果不是當前的節點ID,而滿足查詢條件下的根節點的ID。以上面為例,我們需要得到以上結果只需要執行以下語句就可以搞定了:
select CONNECT_BY_ROOT dirindex, fatherindex, RPAD('' '', 2*(LEVEL-1)) || dirname from t_tonedirlib
start with fatherindex = 0
connect by fatherindex = prior dirindex
CONNECT_BY_ROOTDIRINDEX FATHERINDEX RPAD('''',2*(LEVEL-1))||DIRNAME
----------------------- ------------- -----------------------------
1 0 中文經典
1 1 kkkkkkk
1 52 222
1 52 sixx
1 52 seven
1 52 uiouoooo
1 52 four
1 1 流行風雲
1 1 影視金曲
1 8 aaa
1 8 bbb
1 8 ccc
1 1 古典音樂
1 1 小熊之家
1 81 龍珠
1 81 snoppy
1 81 叮當1
1 81 龍貓
1 81 叮當2
2 0 熱門流行
2 2 有獎活動
2 2 相約香格裡拉
2 2 新浪彩鈴
3 0 老歌回放
3 3 老電影
3 3 懷舊金曲
26 rows selected
查出來的結果中,CONNECT_BY_ROOTDIRINDEX就是各個子類(孫子類)所屬的大類編號,如果需要統計,就只要執行以下語句馬上可以統計出來了:
select rootindex, count(''X'') from
(select CONNECT_BY_ROOT dirindex as rootindex
from t_tonedirlib
start with fatherindex = 0
connect by fatherindex = prior dirindex) a
group by a.rootindex
ROOTINDEX COUNT(''X'')
--------- ----------
1 19
2 4
3 3
3 rows selected
經常有DBA因為要查找樹狀表中的葉子節點而苦惱。大部分DBA為了解決這個問題就給表增加了一個字段來描述這個節點是否為葉子節點。但這樣做有很大的弊端:需要通代碼邏輯來保證這個字段的正確性。
Oracle 10G中提供了一個新特性——CONNECT_BY_ISLEAF——來解決這個問題了。簡單點說,這個屬性結果表明當前節點在滿足條件的查詢結果中是否為葉子節點, 0不是,1是:
select CONNECT_BY_ISLEAF, dirindex, fatherindex, RPAD('' '', 2*(LEVEL-1)) || dirname
from t_tonedirlib
start with fatherindex = 0
connect by fatherindex = prior dirindex
CONNECT_BY_ISLEAF DIRINDEX FATHERINDEX RPAD('' '',2*(LEVEL-1))||dirname
----------------- ---------------- ---------------------------------
0 1 0 中文經典 0 52 1 kkkkkkk
1 70 52 222
1 58 52 sixx
1 59 52 seven
1 69 52 uiouoooo
1 55 52 four
1 7 1 流行風雲
0 8 1 影視金曲
1 1111 8 aaa
1 1112 8 bbb
1 1113 8 ccc
1 9 1 古典音樂
0 81 1 小熊之家
1 104 81 龍珠
1 105 81 snoppy
1 101 81 叮當1
1 102 81 龍貓
1 103 81 叮當2
0 2 0 熱門流行
1 31 2 有獎活動
1 32 2 相約香格裡拉
1 50 2 新浪彩鈴
0 3 0 老歌回放
1 333 3 老電影
1 335 3 懷舊金曲
26 rows selected
一看結果,清晰明了!
我們的樹狀屬性一般都是在一條記錄中記錄一個當前節點的ID和這個節點的父ID來實現。但是,一旦數據中出現了循環記錄,如兩個節點互為對方父節點,系統就會報ORA-01436錯誤:
insert into t_tonedirlib(dirindex, fatherindex, dirname, status) values (666, 667, ''123'', 5);
1 row inserted
insert into t_tonedirlib(dirindex, fatherindex, dirname, status) values (667, 666, ''456'', 5);
1 row inserted
select dirindex, fatherindex, RPAD('' '', 2*(LEVEL-1)) || dirname from t_tonedirlib
start with fatherindex = 666
connect by fatherindex = prior dirindex
ORA-01436: 用戶數據中的 CONNECT BY 循環
select CONNECT_BY_ISCYCLE, dirindex, fatherindex, RPAD('' '', 2*(LEVEL-1)) || dirname
from t_tonedirlib
start with fatherindex = 666
connect by NOCYCLE fatherindex = prior dirindex
CONNECT_BY_ISCYCLE DIRINDEX FATHERINDEX RPAD('' '',2*(LEVEL-1))||dirname
----------------- ---------------- ---------------------------------
0 667 666 456
1 666 667 123
2 rows selected
以上就是在