Oracle一个典型行列转换的几种实现方法
2009-08-24 17:00
691 查看
假如有如下表,其中各个i值对应的行数是不定的
SQL> select * from t;
I A D
---------- ---------- -------------------
1 b 2008-03-27 10:55:42
1 a 2008-03-27 10:55:46
1 d 2008-03-27 10:55:30
2 z 2008-03-27 10:55:55
2 t 2008-03-27 10:55:59
要获得如下结果,注意字符串需要按照D列的时间排序:
1 d,b,a
2 z,t
这是一个比较典型的行列转换,有好几种实现方法
1.自定义函数实现
create or replace function my_concat(n number)
return varchar2
is
type typ_cursor is ref cursor;
v_cursor typ_cursor;
v_temp varchar2(10);
v_result varchar2(4000):= '';
v_sql varchar2(200);
begin
v_sql := 'select a from t where i=' || n ||' order by d';
open v_cursor for v_sql;
loop
fetch v_cursor into v_temp;
exit when v_cursor%notfound;
v_result := v_result ||',' || v_temp;
end loop;
return substr(v_result,2);
end;
SQL> select i,my_concat(i) from t group by i;
I MY_CONCAT(I)
---------- --------------------
1 d,b,a
2 z,t
虽然这种方式可以实现需求,但是如果表t的数据量很大,i的值又很多的情况下,因为针对每个i值都要执行一句select,扫描和排序的次数和i的值成正比,性能会非常差。
2.使用sys_connect_by_path
select i,ltrim(max(sys_connect_by_path(a,',')),',') a
from
(
select i,a,d,min(d) over(partition by i) d_min,
(row_number() over(order by i,d))+(dense_rank() over (order by i)) numid
from t
)
start with d=d_min connect by numid-1=prior numid
group by i;
从执行计划上来看,这种方式只需要扫描两次表,比自定义函数的方法,效率要高很多,尤其是表中数据量较大的时候:
![](http://www.ningoo.net/wp-content/uploads/2008/03/eplan1.JPG)
3.使用wm_sys.wm_concat
这个函数也可以实现类似的行列转换需求,但是似乎没有办法做到直接根据另外一列排序,所以需要先通过子查询或者临时表排好序
SQL> select i,wmsys.wm_concat(a) from t group by i;
I WMSYS.WM_CONCAT(A)
---------- --------------------
1 b,a,d
2 z,t
SQL> select i,wmsys.wm_concat(a)
2 from
3 (select * from t order by i,d)
4 group by i;
I WMSYS.WM_CONCAT(A)
---------- --------------------
1 d,b,a
2 z,t
执行计划上看,只需要做一次表扫描就可以了,但是这个函数是加密过的,执行计划并不能显示函数内部的操作。
![](http://www.ningoo.net/wp-content/uploads/2008/03/eplan2.JPG)
不知道大家还有没有更加高效的实现方式,欢迎指教^_^
http://www.ningoo.net/html/2008/how_to_do_string_aggregate_on_oracle.html
Introduction of WMSYS
WMSSYS is used to store all the metadata information for Oracle Workspace Manager. This user was introduced in Oracle9i and (like most Oracle9i supporting accounts) is locked by default. The user account is locked because we want the password to be public but restrict access to the account to the SYS schema. So, to unlock the account, DBA privileges are required.
This post will show you on how to use the method WMSSYS.WM_CONCAT to convert the row and columns in data table.
SQL> select version from v$instance;
VERSION
-----------------
10.2.0.1.0
SQL>
SQL> create table IDTABLE
2 (
3 id number,
4 val varchar2(20)
5 )
6 ;
Table created
SQL>
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'abc');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'abc');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'def');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'def');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'ghi');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'jkl');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'mno');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'mno');
1 row inserted
SQL> select id,val from idtable;
ID VAL
---------- --------------------
10 abc
10 abc
10 def
10 def
20 ghi
20 jkl
20 mno
20 mno
8 rows selected
SQL> commit;
Commit complete
SQL>
SQL> SELECT ID, WMSYS.WM_CONCAT(VAL) AS ENAMES
2 FROM IDTABLE
3 GROUP BY ID;
ID ENAMES
---------- --------------------------------------------------------------------------------
10 abc,abc,def,def
20 ghi,jkl,mno,mno
SQL>
SQL> SELECT ID, WMSYS.WM_CONCAT(DISTINCT VAL) AS ENAMES
2 FROM IDTABLE
3 GROUP BY ID
4 ORDER BY ID;
ID ENAMES
---------- --------------------------------------------------------------------------------
10 abc,def
20 ghi,jkl,mno
SQL>
SQL> SELECT ID, VAL, WMSYS.WM_CONCAT(VAL) OVER(PARTITION BY ID) AS ENAMES
2 FROM IDTABLE
3 ORDER BY ID;
ID VAL ENAMES
---------- -------------------- --------------------------------------------------------------------------------
10 abc abc,abc,def,def
10 abc abc,abc,def,def
10 def abc,abc,def,def
10 def abc,abc,def,def
20 ghi ghi,jkl,mno,mno
20 jkl ghi,jkl,mno,mno
20 mno ghi,jkl,mno,mno
20 mno ghi,jkl,mno,mno
8 rows selected
SQL>
SQL> SELECT ID, VAL, WMSYS.WM_CONCAT(VAL) OVER(ORDER BY ID, VAL) AS ENAMES
2 FROM IDTABLE
3 ORDER BY ID;
ID VAL ENAMES
---------- -------------------- --------------------------------------------------------------------------------
10 abc abc,abc
10 abc abc,abc
10 def abc,abc,def,def
10 def abc,abc,def,def
20 ghi abc,abc,def,def,ghi
20 jkl abc,abc,def,def,ghi,jkl
20 mno abc,abc,def,def,ghi,jkl,mno,mno
20 mno abc,abc,def,def,ghi,jkl,mno,mno
8 rows selected
http://www.cnblogs.com/mikemao/archive/2009/06/11/1501116.html
SQL> select * from t;
I A D
---------- ---------- -------------------
1 b 2008-03-27 10:55:42
1 a 2008-03-27 10:55:46
1 d 2008-03-27 10:55:30
2 z 2008-03-27 10:55:55
2 t 2008-03-27 10:55:59
要获得如下结果,注意字符串需要按照D列的时间排序:
1 d,b,a
2 z,t
这是一个比较典型的行列转换,有好几种实现方法
1.自定义函数实现
create or replace function my_concat(n number)
return varchar2
is
type typ_cursor is ref cursor;
v_cursor typ_cursor;
v_temp varchar2(10);
v_result varchar2(4000):= '';
v_sql varchar2(200);
begin
v_sql := 'select a from t where i=' || n ||' order by d';
open v_cursor for v_sql;
loop
fetch v_cursor into v_temp;
exit when v_cursor%notfound;
v_result := v_result ||',' || v_temp;
end loop;
return substr(v_result,2);
end;
SQL> select i,my_concat(i) from t group by i;
I MY_CONCAT(I)
---------- --------------------
1 d,b,a
2 z,t
虽然这种方式可以实现需求,但是如果表t的数据量很大,i的值又很多的情况下,因为针对每个i值都要执行一句select,扫描和排序的次数和i的值成正比,性能会非常差。
2.使用sys_connect_by_path
select i,ltrim(max(sys_connect_by_path(a,',')),',') a
from
(
select i,a,d,min(d) over(partition by i) d_min,
(row_number() over(order by i,d))+(dense_rank() over (order by i)) numid
from t
)
start with d=d_min connect by numid-1=prior numid
group by i;
从执行计划上来看,这种方式只需要扫描两次表,比自定义函数的方法,效率要高很多,尤其是表中数据量较大的时候:
3.使用wm_sys.wm_concat
这个函数也可以实现类似的行列转换需求,但是似乎没有办法做到直接根据另外一列排序,所以需要先通过子查询或者临时表排好序
SQL> select i,wmsys.wm_concat(a) from t group by i;
I WMSYS.WM_CONCAT(A)
---------- --------------------
1 b,a,d
2 z,t
SQL> select i,wmsys.wm_concat(a)
2 from
3 (select * from t order by i,d)
4 group by i;
I WMSYS.WM_CONCAT(A)
---------- --------------------
1 d,b,a
2 z,t
执行计划上看,只需要做一次表扫描就可以了,但是这个函数是加密过的,执行计划并不能显示函数内部的操作。
不知道大家还有没有更加高效的实现方式,欢迎指教^_^
http://www.ningoo.net/html/2008/how_to_do_string_aggregate_on_oracle.html
Introduction of WMSYS
WMSSYS is used to store all the metadata information for Oracle Workspace Manager. This user was introduced in Oracle9i and (like most Oracle9i supporting accounts) is locked by default. The user account is locked because we want the password to be public but restrict access to the account to the SYS schema. So, to unlock the account, DBA privileges are required.
This post will show you on how to use the method WMSSYS.WM_CONCAT to convert the row and columns in data table.
SQL> select version from v$instance;
VERSION
-----------------
10.2.0.1.0
SQL>
SQL> create table IDTABLE
2 (
3 id number,
4 val varchar2(20)
5 )
6 ;
Table created
SQL>
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'abc');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'abc');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'def');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (10, 'def');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'ghi');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'jkl');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'mno');
1 row inserted
SQL> insert into IDTABLE (ID, VAL)
2 values (20, 'mno');
1 row inserted
SQL> select id,val from idtable;
ID VAL
---------- --------------------
10 abc
10 abc
10 def
10 def
20 ghi
20 jkl
20 mno
20 mno
8 rows selected
SQL> commit;
Commit complete
SQL>
SQL> SELECT ID, WMSYS.WM_CONCAT(VAL) AS ENAMES
2 FROM IDTABLE
3 GROUP BY ID;
ID ENAMES
---------- --------------------------------------------------------------------------------
10 abc,abc,def,def
20 ghi,jkl,mno,mno
SQL>
SQL> SELECT ID, WMSYS.WM_CONCAT(DISTINCT VAL) AS ENAMES
2 FROM IDTABLE
3 GROUP BY ID
4 ORDER BY ID;
ID ENAMES
---------- --------------------------------------------------------------------------------
10 abc,def
20 ghi,jkl,mno
SQL>
SQL> SELECT ID, VAL, WMSYS.WM_CONCAT(VAL) OVER(PARTITION BY ID) AS ENAMES
2 FROM IDTABLE
3 ORDER BY ID;
ID VAL ENAMES
---------- -------------------- --------------------------------------------------------------------------------
10 abc abc,abc,def,def
10 abc abc,abc,def,def
10 def abc,abc,def,def
10 def abc,abc,def,def
20 ghi ghi,jkl,mno,mno
20 jkl ghi,jkl,mno,mno
20 mno ghi,jkl,mno,mno
20 mno ghi,jkl,mno,mno
8 rows selected
SQL>
SQL> SELECT ID, VAL, WMSYS.WM_CONCAT(VAL) OVER(ORDER BY ID, VAL) AS ENAMES
2 FROM IDTABLE
3 ORDER BY ID;
ID VAL ENAMES
---------- -------------------- --------------------------------------------------------------------------------
10 abc abc,abc
10 abc abc,abc
10 def abc,abc,def,def
10 def abc,abc,def,def
20 ghi abc,abc,def,def,ghi
20 jkl abc,abc,def,def,ghi,jkl
20 mno abc,abc,def,def,ghi,jkl,mno,mno
20 mno abc,abc,def,def,ghi,jkl,mno,mno
8 rows selected
http://www.cnblogs.com/mikemao/archive/2009/06/11/1501116.html
相关文章推荐
- Oracle一个典型行列转换的几种实现方法(转)
- Oracle一个典型行列转换的几种实现方法
- Oracle一个典型行列转换的几种实现方法(转)
- Oracle一个典型行列转换的几种实现方法
- Oracle一个典型行列转换的几种实现方法
- Oracle典型行列转换的几种实现方法
- Oracle典型行列转换的几种实现方法
- Oracle学习之路-- 案例分析实现行列转换的几种方式
- (转)Oracle中实现行列转换的方法
- Oracle实现行列转换的方法分析
- Oracle实现行列转换的方法分析
- Oracle行列转换的几种方法
- Oracle行列转换实现方法总结
- Oracle实现行列转换的方法分析
- Oracle中实现行列转换的方法
- 一个虚拟空间,不用子目录绑定功能实现建多站(一个空间绑定多个域名实现自动跳转的几种方法!)
- java中有几种方法可以实现一个线程?
- 使用C#实现只允许运行一个程序实例的几种方法
- Oracle行列转换的简单实现
- sqlserver2005 行列转换实现方法