sys_connect_by_path 用法
個人覺得這個函數其實很好用,sys_connect_by_path(字段名, 2個字段之間的連接符號),注意這里的連接符號不要使用逗號,oracle會報錯,如果一定要用,可以使用replace替換一下,方法如下 REPLACE(字段名,原字符,',')。
還有,這個函數使用之前必須先建立一個樹,否則無用。
舉個例子:
目的:將num值相等的項目寫成 seq1,seq2,seq3,……的形式
(SELECT num,REPLACE(MAX(sql0), ';', ',')
???????????????????????? FROM (SELECT num, sys_connect_by_path(sql1, ';') AS sql0
????????????????????????????? FROM (SELECT num, sql1, rn, lead(rn) over(PARTITION BY num ORDER BY rn) rn1
?????????????????????????????????????? FROM (SELECT num, sql1, row_number() over(ORDER BY num, sql1 DESC) rn FROM tlsbk))
????????????????????????????? START WITH num = '1' AND rn1 IS NULL
?????????????????????????????? CONNECT BY rn1 = PRIOR rn));
結果:
num REPLACE(MAX(sql0), ';', ',')
--------------------------------------------------------
1 sql0,sql1,sql2
2 sql20,sql21,sql23,sql24,sql25
3 sql30,sql31,sql32,sql33,sql34,sql35,sql36
樹結構和它的專用函數SYS_CONNECT_BY_PATH(網摘:http://blog.oracle.com.cn/html/83/t-122083.html)
簡單的樹型結構
關于樹的普通應用
學習了下這個函數, 用ORGINDUSTRIES的表做了個測試:
正常的樹型結構
select lpad(' ',6*(level-1))||industry,indlevel,indid,pindid
from ORGINDUSTRIES
start with indid=1
connect by pindid=prior indid
結果顯示如下
??????????????? Indlevel?? indid pindid
?????? 服裝與服飾???????????? 1????????? 1????????? 0
???????????? 服裝???????????? 2????????? 2???????????? 1
?????????????????? 女裝??????? 3????????? 3???????????? 2
倒型樹
下面這個例子是個”倒數”—倒過來的樹型結構
select lpad(' ',6*(level-1))||industry,indlevel,indid,pindid
from ORGINDUSTRIES
start with indid=20
connect by indid=prior pindid;
這是標準結果:
??????????????????????????? Indlevel indid pindid
二手服裝?????????????????? 3??????? 20??? 2
?? 服裝??????????????????? 2??????? 2??????? 1
???????? 服裝與服飾??????? 1??????? 1??????? 0
結論
無論正樹還是倒樹, 關鍵就在于connect by的條件.
正樹:?? 必須是?? ‘父’= prior ‘子’
倒樹:?? 必須是?? ‘子’= prior ‘父’
樹型結構的條件過濾
采用樹型結構的話, 如果我們想將樹上的一個分支砍掉.?? 將分支后面的結構都拋棄掉, 這個可以實現麼?當然可以。 但是不是用where, where條件只能去除單一的條件。
所以, 這種樹型的過濾條件就需要加在connect by上面。
測試如下:由于用真實環境比較貼近實際,所以提前用下SYS_CONNECT_BY_PATH函數來顯示下環境
不加任何條件的環境:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
start with areaname='中國大陸'
connect by parentareaid=prior areaid?
結果:
1??????? 中國大陸,中國大陸
2??????? 北京??????? ,中國大陸,北京
3??????? 北京??????? ,中國大陸,北京,北京
4??????? 東城區??????? ,中國大陸,北京,東城區
5??????? 西城區??????? ,中國大陸,北京,西城區
22??????? 廣東??????? ,中國大陸,廣東
23??????? 廣州??????? ,中國大陸,廣東,廣州
24??????? 汕尾??????? ,中國大陸,廣東,汕尾
25??????? 潮陽??????? ,中國大陸,廣東,潮陽
46??????? 上海??????? ,中國大陸,上海
47??????? 上海??????? ,中國大陸,上海,上海
48??????? 黃浦區??????? ,中國大陸,上海,黃浦區
49??????? 閘北區??????? ,中國大陸,上海,閘北區
加了where過濾條件的SQL:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
where bb.areaid>861000
start with areaname='中國大陸'
connect by parentareaid=prior areaid
結果為:
2??????? 北京??????? ,中國大陸,北京
3??????? 北京??????? ,中國大陸,北京,北京
4??????? 東城區??????? ,中國大陸,北京,東城區
5??????? 西城區??????? ,中國大陸,北京,西城區
22??????? 廣東??????? ,中國大陸,廣東
23??????? 廣州??????? ,中國大陸,廣東,廣州
24??????? 汕尾??????? ,中國大陸,廣東,汕尾
25??????? 潮陽??????? ,中國大陸,廣東,潮陽
46??????? 上海??????? ,中國大陸,上海
47??????? 上海??????? ,中國大陸,上海,上海
48??????? 黃浦區??????? ,中國大陸,上海,黃浦區
49??????? 閘北區??????? ,中國大陸,上海,閘北區
結論:去掉了“1??????? 中國大陸,中國大陸”數據
加了connect by的過濾條件:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
where bb.areaid>861000
start with areaname='中國大陸'
connect by parentareaid=prior areaid?? and areaname<>'廣東'
結果為:
2??????? 北京??????? ,中國大陸,北京
3??????? 北京??????? ,中國大陸,北京,北京
4??????? 東城區??????? ,中國大陸,北京,東城區
5??????? 西城區??????? ,中國大陸,北京,西城區
46??????? 上海??????? ,中國大陸,上海
47??????? 上海??????? ,中國大陸,上海,上海
48??????? 黃浦區??????? ,中國大陸,上海,黃浦區
49??????? 閘北區??????? ,中國大陸,上海,閘北區
結論:去掉了整個廣東的分支,?? 在結果集中只有北京和上海
SYS_CONNECT_BY_PATH函數
采用SYS_CONNECT_BY_PATH函數為:
select industry,sys_connect_by_path(industry,'/')
from ORGINDUSTRIES
start with indid=3
connect by indid=prior pindid;
結果為:
女裝???????????? /女裝
服裝???????????? /女裝/服裝
服裝與服飾????????? /女裝/服裝/服裝與服飾
這樣的話, 就可以實現, 樹結構的結果集的單行拼接:
我們只需要取最大的字段就OK了
測試如下:
select max(sys_connect_by_path(industry,'/'))
from ORGINDUSTRIES
start with indid=3
connect by indid=prior pindid;
結果為:
/女裝/服裝/服裝與服飾
復雜的樹型結構――多列變單列
樹型結構也分單樹和多樹(我的稱呼,實際上就是指單支和多支)
對于下面的這種情況, 我們必須要構造的樹就屬于單支樹。
原始環境
環境如下:
select * from test;
結果為:
1??????? n1
1??????? n2
1??????? n3
1??????? n4
1??????? n5
3??????? t1
3??????? t2
3??????? t3
3??????? t4
3??????? t5
3??????? t6
2??????? m1
造樹
腳本如下:
select no,q,
?? no+row_number() over( order by no) rn,
?? row_number() over(partition by no order by no) rn1
from test
結果如下:
No?? Q?? RN RN1
1??????? n1??????? 2??????? 1
1??????? n2??????? 3??????? 2
1??????? n3??????? 4??????? 3
1??????? n4??????? 5??????? 4
1??????? n5??????? 6??????? 5
2??????? m1??????? 8??????? 1
3??????? t1??????? 10??????? 1
3??????? t2??????? 11??????? 2
3??????? t3??????? 12??????? 3
3??????? t4??????? 13??????? 4
3??????? t5??????? 14??????? 5
3??????? t6??????? 15??????? 6
每列的目的是:
RN1列主要的目的是分組, 按照value值‘1’,我們可以start with使用它。
RN列主要用來做connect by使用。 實際上它就是我們要的樹。
第一個支: 2,3,4,5,6
第二個支: 8
第三個支: 10,11,12,13,14,15
中間為什么要斷掉:7,9?? 目的就是為了區別每個分支。 到后面看具體的SQL,就明白這里的說法了。
殺手锏
既然我們有了樹, 就可以使用樹型函數SYS_CONNECT_BY_PATH和connect by啦,來拼接我們所需要的多列值。
腳本如下:
select no,sys_connect_by_path(q,',')
from (
select no,q,
?? no+row_number() over( order by no) rn,
?? row_number() over(partition by no order by no) rn1
from test
)
start with rn1=1
connect by rn-1=prior rn
結果為:
1??????? ,n1
1??????? ,n1,n2
1??????? ,n1,n2,n3
1??????? ,n1,n2,n3,n4
1??????? ,n1,n2,n3,n4,n5
2??????? ,m1
3??????? ,t1
3??????? ,t1,t2
3??????? ,t1,t2,t3
3??????? ,t1,t2,t3,t4
3??????? ,t1,t2,t3,t4,t5
3??????? ,t1,t2,t3,t4,t5,t6
終極武器
最終我們要的值,是單列值, 其實想想, 也就是最長的一行咯。 那么就好辦了。 我們直接GROUP BY ,然后取MAX值。
腳本如下:
select no,max(sys_connect_by_path(q,','))
from (
select no,q,
?? no+row_number() over( order by no) rn,
?? row_number() over(partition by no order by no) rn1
from test
)
start with rn1=1
connect by rn-1=prior rn
group by no
結果為:
1??????? ,n1,n2,n3,n4,n5
2??????? ,m1
3??????? ,t1,t2,t3,t4,t5,t6
如果覺得前面的‘,’不好看,可以使用ltrim去掉。 或者用substr也可以。
如下:
ltrim(max(sys_connect_by_path(q,',')),',')
或者
substr(max(sys_connect_by_path(q,',')),2)
總結
以上是生活随笔為你收集整理的sys_connect_by_path 用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Data JPA 从入门到
- 下一篇: 网络计算机显示10,win10电脑网络显