请教一个复杂的oracle查询语句(100分)

  • 主题发起人 主题发起人 johnnywong
  • 开始时间 开始时间
J

johnnywong

Unregistered / Unconfirmed
GUEST, unregistred user!
表A :纪录如下<br>网上代理号 &nbsp; 收件人 &nbsp;地址 &nbsp; &nbsp; &nbsp; &nbsp; 联系电话 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 编号 <br>H76 &nbsp; &nbsp;胡A 敬龙布艺城 &nbsp; &nbsp; &nbsp; &nbsp; 23360313 &nbsp; &nbsp; &nbsp; &nbsp;HH003269905CN<br> <br>H47 &nbsp; &nbsp;吴A 志达 &nbsp; &nbsp; &nbsp; &nbsp; 23882238 &nbsp; &nbsp; &nbsp; &nbsp;HH003270316CN<br> <br>H21 &nbsp; &nbsp;叶A 沙头大道140号 &nbsp; &nbsp; &nbsp;13XXX828071 &nbsp; &nbsp; &nbsp; &nbsp;HH003270611CN <br>H49 &nbsp; &nbsp;叶A 沙头大道140号 &nbsp; &nbsp; &nbsp;13XXX828071 &nbsp; &nbsp; &nbsp; &nbsp;HH003270611CN <br>H97 &nbsp; &nbsp;叶A 沙头大道140号 &nbsp; &nbsp; &nbsp;13XXX828071 &nbsp; &nbsp; &nbsp; &nbsp;HH003270611CN <br>H00 &nbsp; &nbsp;叶A 沙头大道140号 &nbsp; &nbsp; &nbsp;13XXX828071 &nbsp; &nbsp; &nbsp; &nbsp;HH003270611CN<br> <br>H73 &nbsp; &nbsp;苏A 晖楼强虹公司 &nbsp; &nbsp; &nbsp; 13XXX930094 &nbsp; &nbsp; &nbsp; &nbsp;HH003273768CN <br>H92 &nbsp; &nbsp;苏A 晖楼强虹公司 &nbsp; &nbsp; &nbsp; 13XXX930094 &nbsp; &nbsp; &nbsp; &nbsp;HH003273768CN <br>H48 &nbsp; &nbsp;苏A 晖楼强虹公司 &nbsp; &nbsp; &nbsp; 13XXX930094 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;HH003273768CN <br><br><br>根据编号相同的,将对应的'网上代理号'合并,各个‘网上代理号’用'/'隔开,需要的查询结果是:(如下)<br><br>网上代理号 &nbsp; &nbsp; &nbsp; &nbsp; 收件人 地址 &nbsp; &nbsp; &nbsp;联系电话 编号 <br>H76 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;胡A 敬龙布艺城 &nbsp; &nbsp; &nbsp;23360313 &nbsp; &nbsp;HH003269905CN<br> <br>H47 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;吴A 志达 &nbsp; &nbsp; &nbsp;23882238 &nbsp; &nbsp;HH003270316CN<br><br>H21/H49/H97/H00 &nbsp; &nbsp; 叶A 沙头大道140号 &nbsp; 13XXX828071 &nbsp;HH003270611CN<br>H73/H92/H48 &nbsp; &nbsp; &nbsp; &nbsp; 苏A 晖楼强虹公司 &nbsp; &nbsp;13XXX930094 &nbsp;HH003273768CN<br><br>请问改如何操作?
 
数据库中分组字符串相加<br>SQL&gt; select * from test;<br><br>ID MC<br>---------- -------------<br>1 11111<br>1 22222<br>2 11111<br>2 22222<br>3 11111<br>3 22222<br>3 33333<br><br>已选择7行。<br><br>SQL&gt; select id,ltrim(max(sys_connect_by_path(mc,',')),',') row2col<br>from (select id,mc,<br>id+(row_number() over(order by id)) node_id,<br>row_number() over(partition by id order by id) rn<br>from test)<br>start with rn = 1<br>connect by node_id-1 = prior node_id<br>group by id<br>order by id;<br><br>ID ROW2COL<br>---------- -------------------------------------------------------------<br>1 11111,22222<br>2 11111,22222<br>3 11111,22222,33333<br><br>SQL&gt; select id,replace(max(sys_connect_by_path(mc,',')),',') row2col<br>from (select id,mc,<br>id+(row_number() over(order by id)) node_id,<br>row_number() over(partition by id order by id) rn<br>from test)<br>start with rn = 1<br>connect by node_id-1 = prior node_id<br>group by id<br>order by id;<br><br>ID ROW2COL<br>---------- ------------------------------------------------------------<br>1 1111122222<br>2 1111122222<br>3 111112222233333<br><br><br><br><br>--该测试脚本可以直接运行<br><br>--现在想把数据库中数据按照固定字段分组相加,这里总结了三种方法。<br><br>--创建测试表、添加测试数据<br><br>create table test(id varchar2(10),mc varchar2(50));<br>insert into test values('1','11111');<br>insert into test values('1','22222');<br>insert into test values('2','11111');<br>insert into test values('2','22222');<br>insert into test values('3','11111');<br>insert into test values('3','22222');<br>insert into test values('3','33333');<br>commit;<br><br>--方法一:<br><br><br>set serveroutput on size 1000000 <br>declare <br>union_mc varchar2(200); <br>begin <br>for cur_a in(select distinct id from test) loop <br>for cur_b in(select mc from test where id=cur_a.id) loop <br>union_mc:=union_mc||cur_b.mc; <br>end loop; <br>dbms_output.put_line(cur_a.id||chr(9)||union_mc); <br>union_mc := ''; <br>end loop; <br>end; <br>/ <br><br>--方法二:<br><br>CREATE OR REPLACE function link(v_id varchar2) <br>return varchar2 <br>is <br>union_mc varchar2(200); <br>begin <br>for cur in (select mc from test where id=v_id) loop <br>union_mc := union_mc||cur.mc; <br>end loop; <br>union_mc := rtrim(union_mc,1); <br>return union_mc; <br>end; <br>/ <br><br>select id,link(id) from test group by id;<br><br>--方法三:<br><br>/*从Oracle 9i开始,开发者可以创建用户自定义的合计函数,除了PL/SQL外,还可以使用任何Oralce所支持的语言(如C++或者Java)来创建合计函数。TYPE头定义必须包含ODCIAggregateInitialize、ODCIAggregateIterate、ODCIAggregateMerge和ODCIAggregateTerminate这四个接口函数。*/<br><br>/*Initialize函数对数据组各个需要处理的字段各运行一次。自然的,我需要为每一个值准备一个新的清单,所以需要初始化持久变量list,这里初始化值为null。*/<br><br>/*Iterate函数处理返回的行,所以实际上是由它来创建返回的值的清单。先测试list是否为空,如果为空,就把list直接设置为所引入的value值;如果list变量非空,则给list添加一个逗号后再插入value值,list的最大允许字符数32767。*/ <br><br>/*Terminate函数在数据组的每个行的感兴趣字段数据被处理后执行。在这个函数中我只需简单的返回清单变量即可。*/ <br><br>/*Merge函数,用来返回成功标记的。*/<br><br>/*创建自己的合计函数扩展了Oracle统计和文本处理能力。*/<br><br><br>create or replace type t_cat as object <br>( <br>union_mc VARCHAR2(200), <br>static function ODCIAggregateInitialize(sctx IN OUT t_cat) return number, <br>member function ODCIAggregateIterate(self IN OUT t_cat,value IN varchar2) return number, <br>member function ODCIAggregateTerminate(self IN t_cat,returnValue OUT varchar2, flags IN number) return number, <br>member function ODCIAggregateMerge(self IN OUT t_cat,ctx2 IN t_cat) return number <br>); <br><br>create or replace type body t_cat is <br>static function ODCIAggregateInitialize(sctx IN OUT t_cat ) <br>return number is <br>begin <br>sctx := t_cat(''); <br>return ODCIConst.Success; <br>end; <br><br>member function ODCIAggregateIterate(self IN OUT t_cat, value IN varchar2) <br>return number is <br>begin <br>self.union_mc := self.union_mc || value; <br>return ODCIConst.Success; <br>end; <br><br>member function ODCIAggregateTerminate(self IN t_cat, returnValue OUT varchar2, flags IN number) return number is <br>begin <br>returnValue := self.union_mc; <br>return ODCIConst.Success; <br>end; <br><br>member function ODCIAggregateMerge(self IN OUT t_cat , ctx2 IN t_cat ) return number is <br>begin <br>return ODCIConst.Success; <br>end; <br>end; <br>/<br><br>/*如果你的Oracle服务器没有配置成支持并行处理的方式,可以去掉参数PARALLEL_ENABLE*/<br><br>create or replace function catstr(v_mc varchar2) return varchar2 PARALLEL_ENABLE AGGREGATE USING t_cat; <br>/<br><br>select id,catstr(mc) from test group by id;
 
先增加一个ColumnToRow行变列函数<br>--该sql生成了一个名为list的函数。功能是将多行的数据记录转换成一行的记录,各数据用“参数的第一位字符隔开”分隔。<br>--使用样例:select ColumnToRow(','||Tname) from tab where rownum&lt;10;<br><br>create or replace type list_agg as object<br>(<br>total varchar2(4000),<br><br>static function<br>ODCIAggregateInitialize(sctx IN OUT list_agg )<br>return number,<br><br>member function<br>ODCIAggregateIterate(self IN OUT list_agg ,<br>value IN varchar2 )<br>return number,<br><br>member function<br>ODCIAggregateTerminate(self IN list_agg,<br>returnValue OUT varchar2,<br>flags IN number)<br>return number,<br><br>member function<br>ODCIAggregateMerge(self IN OUT list_agg,<br>ctx2 IN list_agg)<br>return number<br>);<br>/<br><br>create or replace type body list_agg<br>is<br><br>static function ODCIAggregateInitialize(sctx IN OUT list_agg)<br>return number<br>is<br>begin<br>sctx := list_agg(null);<br>return ODCIConst.Success;<br>end;<br><br>member function ODCIAggregateIterate(self IN OUT list_agg,<br>value IN varchar2 )<br>return number<br>is<br>begin<br>self.total := self.total||value;<br>return ODCIConst.Success;<br>end;<br><br>member function ODCIAggregateTerminate(self IN list_agg,<br>returnValue OUT varchar2,<br>flags IN number)<br>return number<br>is<br>begin<br>returnValue := substr(self.total,2);<br>return ODCIConst.Success;<br>end;<br><br>member function ODCIAggregateMerge(self IN OUT list_agg,<br>ctx2 IN list_agg)<br>return number<br>is<br>begin<br>self.total := self.total||ctx2.total;<br>return ODCIConst.Success;<br>end;<br><br><br>end;<br><br>/<br><br>CREATE OR REPLACE FUNCTION ColumnToRow(input varchar2 )<br>RETURN varchar2<br>PARALLEL_ENABLE AGGREGATE USING list_agg;<br><br>/<br><br>最后用下面的语句查询<br>select &nbsp;收件人,地址,联系电话,编号,ColumnToRow('/'||网上代理号) &nbsp;from 表名 <br>group by 收件人,地址,联系电话,编号
 
to yanfeng1001:<br>你的方法基本能符合要求了,但还有一个关键问题没有解决,如果ID的值含有字母的时候,运行脚本时提示:ORA-01722: 无效数字<br>例:<br>ID MC<br>---------- -------------<br>H1 11111<br>H1 22222<br>H2 11111<br>H2 22222<br>H3 11111<br>H3 22222<br>H3 33333
 
后退
顶部