设为首页 收藏本站
查看: 1320|回复: 0

[经验分享] ORACLE数据库中分组字符串相加

[复制链接]
YunVN网友  发表于 2016-8-16 06:57:14 |阅读模式
来自 http://blog.oracle.com.cn/index.php/233877/viewspace-5271.html
引用
--该测试脚本可以直接运行
--现在想把数据库中数据按照固定字段分组相加,这里总结了三种方法。
--创建测试表、添加测试数据
create table test(id varchar2(10),mc varchar2(50));
insert into test values('1','11111');
insert into test values('1','22222');
insert into test values('2','11111');
insert into test values('2','22222');
insert into test values('3','11111');
insert into test values('3','22222');
insert into test values('3','33333');
commit;

--方法一:

set serveroutput on size 1000000
declare
union_mc varchar2(200);
begin
for cur_a in(select distinct id from test) loop
for cur_b in(select mc from test where id=cur_a.id) loop
union_mc:=union_mc||cur_b.mc;
end loop;
dbms_output.put_line(cur_a.id||chr(9)||union_mc);
union_mc := '';
end loop;
end;
/

--方法二:
CREATE OR REPLACE function link(v_id varchar2) return varchar2 is
union_mc varchar2(200);
begin
for cur in (select mc from test where id = v_id) loop
union_mc := union_mc || cur.mc;
end loop;
union_mc := rtrim(union_mc, 1);
return union_mc;
end;

select id,link(id) from test group by id;
/

--方法三:
/*从Oracle 9i开始,开发者可以创建用户自定义的合计函数,除了PL/SQL外,还可以使用任何Oralce所支持的语言(如C++或者Java)来创建合计函数。TYPE头定义必须包含ODCIAggregateInitialize、ODCIAggregateIterate、ODCIAggregateMerge和ODCIAggregateTerminate这四个接口函数。*/
/*Initialize函数对数据组各个需要处理的字段各运行一次。自然的,我需要为每一个值准备一个新的清单,所以需要初始化持久变量list,这里初始化值为null。*/
/*Iterate函数处理返回的行,所以实际上是由它来创建返回的值的清单。先测试list是否为空,如果为空,就把list直接设置为所引入的value值;如果list变量非空,则给list添加一个逗号后再插入value值,list的最大允许字符数32767。*/
/*Terminate函数在数据组的每个行的感兴趣字段数据被处理后执行。在这个函数中我只需简单的返回清单变量即可。*/
/*Merge函数,用来返回成功标记的。*/
/*创建自己的合计函数扩展了Oracle统计和文本处理能力。*/

create or replace type t_cat as object
(
union_mc VARCHAR2(200),
static function ODCIAggregateInitialize(sctx IN OUT t_cat) return number,
member function ODCIAggregateIterate(self  IN OUT t_cat,
value IN varchar2) return number,
member function ODCIAggregateTerminate(self        IN t_cat,
returnValue OUT varchar2,
flags       IN number)
return number,
member function ODCIAggregateMerge(self IN OUT t_cat, ctx2 IN t_cat)
return number
)
;
create or replace type body t_cat is static function ODCIAggregateInitialize(sctx IN OUT t_cat) return number is begin sctx := t_cat(''); return ODCIConst.Success; end;
member function ODCIAggregateIterate(self IN OUT t_cat, value IN varchar2) return number is begin self.union_mc := self.union_mc || value; return ODCIConst.Success; end;
member function ODCIAggregateTerminate(self IN t_cat, returnValue OUT varchar2, flags IN number) return number is begin returnValue := self.union_mc; return ODCIConst.Success; end;
member function ODCIAggregateMerge(self IN OUT t_cat, ctx2 IN t_cat) return number is begin return ODCIConst.Success; end; end;
/

/*如果你的Oracle服务器没有配置成支持并行处理的方式,可以去掉参数PARALLEL_ENABLE*/
create or replace function catstr(v_mc varchar2) return varchar2
PARALLEL_ENABLE
AGGREGATE USING t_cat;
/
select id, catstr(mc) from test group by id;

方法四:
select id,
mc,
row_number() over(partition by id order by id) rn_by_id,
row_number() over(order by id) + id rn
from test;

/*
利用分析函数,构造两列,做为连接的条件:按照id分组,RN-1等于PRIOR RN作为条件连接。
ID MC RN_BY_ID RN
---------- -------------------------------------------------- ---------- ----------
1 11111 1 2
1 22222 2 3
2 11111 1 5
2 22222 2 6
3 11111 1 8
3 22222 2 9
3 33333 3 10
*/
select id, ltrim(max(sys_connect_by_path(mc, ';')), ';') add_mc
from (select id,
mc,
row_number() over(partition by id order by id) rn_by_id,
row_number() over(order by id) + id rn
from test)
start with rn_by_id = 1
connect by rn - 1 = prior rn
group by id
order by id;

/*
另用sys_connect_by_path函数实现字符串的连接,把最左边的分号去掉,即得到我们想要的结果
ID ADD_MC
---------- --------------------------------------------------------------------------------
1 11111;22222
2 11111;22222
3 11111;22222;33333
*/
select * from test;

方法四的另一种写法
估计类似的写法还有很多,这个和上一个不同在于用的没有带有start with(filter功能)的connect,并借助level和first_value来实现。
SELECT distinct id,
ltrim(first_value(mc_add)
over(partition by id order BY l DESC),
';')
from (SELECT id, LEVEL l, sys_connect_by_path(mc, ';') mc_add
from (select id || rownum rn, id || rownum - 1 rn_small, id, mc
from test)
CONNECT BY PRIOR rn = rn_small);

变换一下:(考虑id不是数字的情况)
select id, ltrim(max(sys_connect_by_path(mc, ';')), ';')
from (select id,
mc,
row_number() over(partition by id order by id) id1,
row_number() over(order by id) + dense_rank() over(order by id) id2
from test)
start with id1 = 1
connect by prior id2 = id2 - 1
group by id
order by id;

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-258322-1-1.html 上篇帖子: Oracle 高速批量速插入数据解决方案 下篇帖子: 详细讲解Oracle表分区相关概念及优点
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表