您的位置:首页 > 数据库 > Oracle

Oracle中分组后拼接分组字符串

2014-05-14 14:57 295 查看
先分组,再把分组后的属于某组的多条记录的某字段进行拼接。

实现方式如下:

/* --创建表 test*/

create table test

(

NO NUMBER,

VALUE VARCHAR2(100),

NAME VARCHAR2(100)

);

/* ----插入数据*/

insert into test

select * from

(

select '1','a','测试1' from dual union all

select '1','b','测试2' from dual union all

select '1','c','测试3' from dual union all

select '1','d','测试4' from dual union all

select '2','e','测试5' from dual union all

select '4','f','测试6' from dual union all

select '4','g','测试7' from dual

);

/*--Sql语句:*/

select No,

ltrim(max(sys_connect_by_path(Value, ';')), ';') as Value,

ltrim(max(sys_connect_by_path(Name, ';')), ';') as Name

from (select No,

Value,

Name,

rnFirst,

lead(rnFirst) over(partition by No order by rnFirst) rnNext

from (select a.No,

a.Value,

a.Name,

row_number() over(order by a.No, a.Value desc) rnFirst

from Test a) tmpTable1) tmpTable2

start with rnNext is null

connect by rnNext = prior rnFirst

group by No;

/*--检索结果如下:*/

/*

NO VALUE NAME

1 a;b;c;d 测试1;测试2;测试3;测试4

2 e 测试5

4 f;g 测试6;测试7

*/

/********************************* 分析 *************************************/

--简单解释一下那个Sql吧:

/*--1、最内层的Sql(即表tmpTable1),按No和Value排序,并列出行号:*/

select a.No,

a.Value,

a.Name,

row_number() over(order by a.No, a.Value desc) rnFirst

from Test a;

/*

该语句结果如下:

NO VALUE NAME RNFIRST

1 d 测试4 1

1 c 测试3 2

1 b 测试2 3

1 a 测试1 4

2 e 测试5 5

4 g 测试7 6

4 f 测试6 7

*/

/*--2、外层的Sql(即表tmpTable2),根据No分区,取出当前行对应的下一条记录的行号字段:*/

select No,

Value,

Name,

rnFirst,

lead(rnFirst) over(partition by No order by rnFirst) rnNext

/*--lead(rnFirst):取得下一行记录的rnFirst字段

--over(partition by No order by rnFirst) 按rnFirst排序,并按No分区,

--分区就是如果下一行的No字段与当前行的No字段不相等时,不取下一行记录显示*/

from (select a.No,

a.Value,

a.Name,

row_number() over(order by a.No, a.Value desc) rnFirst

from Test a) tmpTable1;

/*

--该语句结果如下:

NO VALUE NAME RNFIRST RNNEXT

1 d 测试4 1 2

1 c 测试3 2 3

1 b 测试2 3 4

1 a 测试1 4 NULL

2 e 测试5 5 NULL

4 g 测试7 6 7

4 f 测试6 7 NULL

*/

/*--3、最后就是最外层的sys_connect_by_path函数与start递归了*/

sys_connect_by_path(Value, ';')

start with rnNext is null

connect by rnNext = prior rnFirst

/*

--这个大概意思就是从rnNext为null的那条记录开始,递归查找,

--如果前一记录的rnFirst字段等于当前记录的rnNext字段,就把2条记录的Value用分号连接起来,

--大家可以先试试下面这个没有Max和Group的Sql:

*/

select No,

sys_connect_by_path(Value, ';') as Value,

sys_connect_by_path(Name, ';') as Name

from (select No,

Value,

Name,

rnFirst,

lead(rnFirst) over(partition by No order by rnFirst) rnNext

from (select a.No,

a.Value,

a.Name,

row_number() over(order by a.No, a.Value desc) rnFirst

from Test a) tmpTable1) tmpTable2

start with rnNext is null

connect by rnNext = prior rnFirst

/*

结果是:

NO VALUE NAME

1 ;a ;测试1

1 ;a;b ;测试1;测试2

1 ;a;b;c ;测试1;测试2;测试3

1 ;a;b;c;d ;测试1;测试2;测试3;测试4

2 ;e ;测试5

4 ;f ;测试6

4 ;f;g ;测试6;测试7

*/

/*

--可以看到,每个No的最后一条记录就是我们要的了

--所以在sys_connect_by_path外面套一个Max,再加个Group by No,得到的结果就是行转列的结果了

--最后再加一个Ltrim,去掉最前面的那个分号,完成。

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: