Oracle數據庫每個版本的提高,都伴隨着一些新特性的推出和原有功能的修改。這就致使咱們在進行應用開發,特別是高級特性、函數使用的時候,版本因素每每是須要考量的內容。數據庫
中午一個同事過來諮詢一句SQL的書寫,問題自己不是很複雜。可是以後沒有想到就是因爲Oracle版本的緣由形成了諸多不便。特此記錄下來,爲其餘朋友之鑑。函數
一、 問題表示測試
問題是這樣的,對於一個數據表,結構以下:spa
SQL> desc ABCDE;orm
Name Type Nullable Default Comments排序
-------- -------- -------- ------- --------開發
HOSTALNE CHAR(4) Y it
CARCDE CHAR(3) select
MART1 CHAR(3) bug
MART2 CHAR(3) Y
MART3 CHAR(3) Y
MART4 CHAR(3) Y
MART5 CHAR(3) Y
MART6 CHAR(3) Y
MART7 CHAR(3) Y
MART8 CHAR(3) Y
MART9 CHAR(3) Y
MART10 CHAR(3) Y
MART11 CHAR(3) Y
SEQNO CHAR(2)
需求是這樣,按照carcde進行分組,以seqno的順序將mart1-mart11合併起來進行展示。
問題自己並不複雜,是一個分組排序,以後進行列轉行處理。列之間的合併使用簡單的||操做符就能夠取到比較好的效果。
列轉行是咱們在進行報表和處理中常常遇到的問題。Oracle從9i開始,開發者就不斷推出解決方法。在10g以後,一種簡單的wm_concate函數基本能夠解決這類型問題。
2、初步嘗試解決
筆者特地詢問了同事的環境版本,知道以前是使用的10g以後,打算使用wm_concate函數。
SQL> select * from dbcargrp;
HOSTALNE CARCDE MART1 MART2 MART3 MART4 MART5 MART6 MART7 MART8 MART9 MART10 MART11 SEQNO
-------- ------ ----- ----- ----- ----- ----- ----- ----- ----- ----- ------ ------ -----
0 AA MU LH SQ 3
0 IV MI AF TX CA WY 9W FM BR AQ JK 2
0 PS ZY SC PE AP PJ CZ VM OH MF ZH 1
43 MI LH US NZ SQ LX BD 2
(篇幅緣由,有省略……)
100 ET SN A3 NH LO TP TK JJ MS OZ OU 1
100 JP CA SK OS TG UA SA LH NZ US LX 2
100 SQ AC KF 3
932 VS SQ 1
從業務上看,相同的carcde的狀況下,只有最後的seqno列中存在空置。咱們進行SQL處理。
SQL> select carcde, wm_concat(a) m from (select carcde,
2 trim(mart1) || ',' || trim(mart2) || ',' || trim(mart3) || ',' ||
3 trim(mart4) || ',' || trim(mart5) || ',' || trim(mart6) || ',' ||
4 trim(mart7) || ',' || trim(mart8) || ',' || trim(mart9) || ',' ||
5 trim(mart10) || ',' || trim(mart11) a
6 from dbcargrp
7 order by carcde, seqno) group by carcde;
CARCDE M
------ ------------------------
0 PS,ZY,SC,PE,AP,PJ,CZ,VM,OH,MF,ZH,IV,MI,AF,TX,CA,WY,9W,FM,BR,AQ,JK,AA,MU,LH,SQ,,,,,,,
100 ET,SN,A3,NH,LO,TP,TK,JJ,MS,OZ,OU,JP,CA,SK,OS,TG,UA,SA,LH,NZ,US,LX,SQ,AC,KF,,,,,,,,
111 MS,CA,NH,NZ,SQ,CO,AC,BD,,,
(篇幅緣由,有省略……)
666 LH,LX,MS,SQ,TK,UA,,,,,
777 SQ,OU,,,,,,,,,
8 AF,KL,SQ,,,,,,,,
932 VS,SQ,,,,,,,,,
15 rows selected
應該說,處理是至關完美的,徹底符合業務系統要求。可是,當同事回去後,問題出現了。
3、11g上的詭異狀況
不一會,同事再次聯繫,說回去以後數據不對了。執行結果也出現問題。筆者到機器去進行實驗,也的確如此。結果集合以下:
SQL> select carcde, wm_concat(a) from (select carcde,
2 --seqno,
3 trim(mart1) || ',' || trim(mart2) || ',' || trim(mart3) || ',' ||
4 trim(mart4) || ',' || trim(mart5) || ',' || trim(mart6) || ',' ||
5 trim(mart7) || ',' || trim(mart8) || ',' || trim(mart9) || ',' ||
6 trim(mart10) || ',' || trim(mart11) a
7 from dbcargrp
8 -- where carcde = '000'
9 order by carcde, seqno) group by carcde;
CARCDE WM_CONCAT(A)
------ --------------------------------------------------------------------------------
0 PS,ZY,SC,PE,AP,PJ,CZ,VM,OH,MF,ZH,AA,MU,LH,SQ,,,,,,,,IV,MI,AF,TX,CA,WY,9W,FM,BR,A
100 ET,SN,A3,NH,LO,TP,TK,JJ,MS,OZ,OU,SQ,AC,KF,,,,,,,,,JP,CA,SK,OS,TG,UA,SA,LH,NZ,US,
111 MS,CA,NH,NZ,SQ,CO,AC,BD,,,
(篇幅緣由,有省略……)
124 CA,CZ,MU,MF,3C,,,,,,
932 VS,SQ,,,,,,,,,
15 rows selected
咱們發現,雖然子查詢結果是按照seqno輸入到上層查詢語句中的,可是Oracle卻沒有按照默認順序進行concate操做。數據集合相同的狀況,爲何結果不一樣?惟一的解釋就是Oracle版本的差別。
通過確認,同事使用的環境是Oracle 11g。在10g下能夠正常執行的函數爲何在11g上失效?
無論如何,哪怕就是bug,首先要尋求解決方法。
4、問題解決
既然在11g上出現問題,那麼能夠着手在11g上看看有沒有其餘的解決方案,畢竟高版本的功能更增強大。筆者選擇了listagg函數。
SQL> select carcde, listagg(a,',') within group (order by seqno)from (select carcde,
2 seqno,
3 trim(mart1) || ',' || trim(mart2) || ',' || trim(mart3) || ',' ||
4 trim(mart4) || ',' || trim(mart5) || ',' || trim(mart6) || ',' ||
5 trim(mart7) || ',' || trim(mart8) || ',' || trim(mart9) || ',' ||
6 trim(mart10) || ',' || trim(mart11) a
7 from dbcargrp
8 order by carcde, seqno) group by carcde;
CARCDE LISTAGG(A,',')WITHINGROUP(ORDE
------ --------------------------------------------------------------------------------
0 PS,ZY,SC,PE,AP,PJ,CZ,VM,OH,MF,ZH,IV,MI,AF,TX,CA,WY,9W,FM,BR,AQ,JK,AA,MU,LH,SQ,,,
100 ET,SN,A3,NH,LO,TP,TK,JJ,MS,OZ,OU,JP,CA,SK,OS,TG,UA,SA,LH,NZ,US,LX,SQ,AC,KF,,,,,,
111 MS,CA,NH,NZ,SQ,CO,AC,BD,,,
(篇幅緣由,有省略……)
932 VS,SQ,,,,,,,,,
15 rows selected
最後和同事溝通後,確認項目組運行數據庫肯定在11g上,可使用listagg函數。
5、反思和結論
解決這個案例以後,筆者在不斷反思。相同的數據、相同的語句,由於版本的緣由,能夠形成處理結果的差異。這就須要咱們對開發的應用系統在不一樣版本上進行相對徹底的測試工做,發現這些問題。
另外一方面,筆者猜測Oracle放鬆wm_concate函數功能的緣由,可能也就在於listagg的推出。相對於wm_concate,listagg提供了合併串排序的規範和標準(within group order by),wm_concate默認的排序就沒有了意義。