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默认的排序就没有了意义。