您当前的位置: 首页 > 数据库教程 > Oracle教程 > Oracle多行记录字符串综合操作几种方法

Oracle多行记录字符串综合操作几种方法

作者:guanchaofeng 来源:不详 发布时间: 2009-06-27 20:56 点击:
怎么合并多行记录的字符串,一直是Oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结。 合并 什么是合并多行字符串(连接字符串)呢,例如: SQLdesctest;NameTypeNullableDefaultComments--------------

Oracle多行记录字符串综合操作几种方法

  怎么合并多行记录的字符串,一直是Oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结。
  
  合并
  
  什么是合并多行字符串(连接字符串)呢,例如:
  
  SQL>desctest;NameTypeNullableDefaultComments------------------------------------------COUNTRYVARCHAR2(20)YCITYVARCHAR2(20)YSQL>select*fromtest;COUNTRYCITY----------------------------------------中国台北中国香港中国上海日本东京日本大阪要求得到如下结果集:---------------------------中国台北,香港,上海日本东京,大阪
  
  实际就是对字符实现一个聚合功能。
  
  下面就对几种经常提及的解决方案进行分析(有一个评测标准最高★★★★★):
  
  1.被集合字段范围小且固定型:
  
  灵活性★性能★★★★难度★
  
  这种方法的原理在于你已经知道CITY字段的值有几种,且还不算太多,如果太多这个SQL就会相当的长。看例子:
  
  SQL>selectt.country,2MAX(decode(t.city,'台北',t.city||',',NULL))||3MAX(decode(t.city,'香港',t.city||',',NULL))||4MAX(decode(t.city,'上海',t.city||',',NULL))||5MAX(decode(t.city,'东京',t.city||',',NULL))||6MAX(decode(t.city,'大阪',t.city||',',NULL))7fromtesttGROUPBYt.country8/COUNTRYMAX(DECODE(T.CITY,'台北',T.CIT--------------------------------------------------中国台北,香港,上海,日本东京,大阪,
  
  大家一看,估计就明白了(如果不明白,好好补习MAXDECODE和分组)。这种方法无愧为最笨的方法,但是对某些应用来说,最有效的方法也许就是它。
  
  2.固定表固定字段函数法:
  
  灵活性★★性能★★★★难度★★
  
  此法必须预先知道是哪个表,也就是说一个表就得写一个函数,不过方法1的一个取值就要便捷多了。在大多数应用中,也不会存在大量这种合并字符串的需求。废话完毕,看下面:
  
  定义一个函数:
  
  createorreplacefunctionstr_list(str_ininvarchar2)--分类字段returnvarchar2isstr_listvarchar2(4000)defaultnull;--连接后字符串strvarchar2(20)defaultnull;--连接符号beginforxin(selectTEST.CITYfromTESTwhereTEST.COUNTRY=str_in)loopstr_list:=str_list||str||to_char(x.city);str:=',';endloop;returnstr_list;end;
  
  使用:
  
  SQL>selectDISTINCT(T.country),list_func1(t.country)fromtestt;COUNTRYLIST_FUNC1(T.COUNTRY)------------------------------------中国台北,香港,上海日本东京,大阪SQL>selectt.country,str_list(t.country)fromtesttGROUPBYt.country;COUNTRYSTR_LIST(T.COUNTRY)-------------------------------------------中国台北,香港,上海日本东京,大阪
  
  这个时候,使用分组和求唯一都可以满足要求。它的原理就是,根据唯一的分组字段country,在函数里面再次查询该字段对应的所有被合并列,使用PL/SQL将其合并输出。
  
  3.灵活表函数法灵活性★★★性能★★★难度★★★
  
  该方法是在方法2的基础上,使用动态SQL,将表名和字段名称传入,从而达到灵活的目的。
  
  createorreplacefunctionstr_list2(key_nameinvarchar2,keyinvarchar2,conameinvarchar2,tnameinvarchar2)returnvarchar2astypercisrefcursor;strvarchar2(4000);sepvarchar2(2);valvarchar2(4000);currc;beginopencurfor'select'||coname||'from'||tname||'where'||key_name||'=:x'usingkey;loopfetchcurintoval;exitwhencur%notfound;str:=str||sep||val;sep:=',';endloop;closecur;returnstr;end;SQL>selecttest.country,2str_list2('COUNTRY',test.country,'CITY','TEST')emplist3fromtest4groupbytest.country5/COUNTRYEMPLIST-------------------------------------中国台北,香港,上海日本东京,大阪
  
  4.一条SQL语法:
  
  灵活性★★★★性能★★难度★★★★
  
  一条SQL的法则是某位大师提出的,大家曾经在某个时期都乐此不彼的寻求各种的问题一条SQL法,但是大师的意思似乎被曲解,很多性能差,可读性差,灵活差的SQL都是这个原则产物,所谓画虎不成反成犬类。不过,解决问题始终是第一原则,这里还是给出一个比较有代表性的一条SQL方法。
  
  SELECTcountry,max(substr(city,2))cityFROM(SELECTcountry,sys_connect_by_path(city,',')cityFROM(SELECTcountry,city,country||rnrchild,country||(rn-1)rfatherFROM(SELECTtest.country,test.city,row_number()over(PARTITIONBYtest.countryORDERBYtest.city)rnFROMtest))CONNECTBYPRIORrchild=rfatherSTARTWITHrfatherLIKE'%0')GROUPBYcountry;
  
  下面分步解析,有4个FROM,就有4次结果集的操作。
  
  step1给记录加上序号rnSQL>SELECTtest.country,test.city,row_number()over(PARTITIONBYtest.countryORDERBYtest.city)rn2FROMtest3/COUNTRYCITYRN--------------------------------------------------日本大阪1日本东京2中国上海1中国台北2中国香港3
  
  step2创造子节点父节点:
  
  SQL>SELECTcountry,city,country||rnrchild,country||(rn-1)rfather2FROM3(SELECTtest.country,test.city,row_number()over(PARTITIONBYtest.countryORDERBYtest.city)rn4FROMtest)5/日本大阪日本1日本0日本东京日本2日本1中国上海中国1中国0中国台北中国2中国1中国香港中国3中国2
  
  step3利用sys_connect_by_path生成结果集:
  
  SELECTcountry,sys_connect_by_path(city,',')cityFROM(SELECTcountry,city,country||rnrchild,country||(rn-1)rfatherFROM(SELECTtest.country,test.city,row_number()over(PARTITIONBYtest.countryORDERBYtest.city)rnFROMtest))CONNECTBYPRIORrchild=rfatherSTARTWITHrfatherLIKE'%0'日本,大阪日本,大阪,东京中国,上海中国,上海,台北中国,上海,台北,香港
  
  step4最终步骤,筛选结果集合:
  
  SQL>SELECTcountry,max(substr(city,2))city2FROM3(SELECTcountry,sys_connect_by_path(city,',')city4FROM5(SELECTcountry,city,country||rnrchild,country||(rn-1)rfather6FROM7(SELECTtest.country,test.city,row_number()over(PARTITIONBYtest.countryORDERBYtest.city)rn8FROMtest))9CONNECTBYPRIORrchild=rfatherSTARTWITHrfatherLIKE'%0')10GROUPBYcountry;COUNTRYCITY---------------------------中国上海,台北,香港日本大阪,东京
  
  5.自定义聚合函数:
  
  灵活性★★★★★性能★★★★★难度★★★★★
  
  最后一个方法是我认为“王道”的方法,自定义聚合函数。就如何我在本开始说的,为啥oracle没有这种聚合函数呢?我也不知道,但Oracle提供了聚合函数的API可以让我方便的自己定义聚合函数。
  
  下面给出一个简单的例子:
  
  SQL>SELECTt.country,strcat(t.city)FROMtesttGROUPBYt.country;COUNTRYSTRCAT(T.CITY)--------------------------------------日本东京,大阪中国台北,香港,上海简单吧,和官方的函数一样的便捷高效。函数:CREATEORREPLACEFUNCTIONstrcat(inputvarchar2)RETURNvarchar2PARALLEL_ENABLEAGGREGATEUSINGstrcat_type;TYPE:createorreplacetypestrcat_typeasobject(cat_stringvarchar2(4000),staticfunctionODCIAggregateInitialize(cs_ctxInOutstrcat_type)returnnumber,memberfunctionODCIAggregateIterate(selfInOutstrcat_type,valueinvarchar2)returnnumber,memberfunctionODCIAggregateMerge(selfInOutstrcat_type,ctx2InOutstrcat_type)returnnumber,memberfunctionODCIAggregateTerminate(selfInOutstrcat_type,returnValueOutvarchar2,flagsinnumber)returnnumber)
  
  6.待发掘:
  
  总结,合并字符串还有更多的方法希望大家能发掘,本文的目的主要是抛砖引玉,如果有新的发现我会继续更新方法。需要注意的问题是,本文采用varchar2为例子,所以长度有限制,Oracle的版本对方法的实现也影响。

分享到:
本文"Oracle多行记录字符串综合操作几种方法"由远航站长收集整理而来,仅供大家学习与参考使用。更多网站制作教程尽在远航站长站。
顶一下
(0)
0%
踩一下
(0)
0%
[点击 次] [返回上一页] [打印]
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 密码: 验证码:
关于本站 - 联系我们 - 网站声明 - 友情连接- 网站地图 - 站点地图 - 返回顶部
Copyright © 2007-2013 www.yhzhan.com(远航站长). All Rights Reserved .
远航站长:为中小站长提供最佳的学习与交流平台,提供网页制作与网站编程等各类网站制作教程.
官方QQ:445490277 网站群:26680406 网站备案号:豫ICP备07500620号-4