`
icheng
  • 浏览: 830823 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

  怎么合并多行记录的字符串,一直是Oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结。

  合并

  什么是合并多行字符串(连接字符串)呢,例如:

  SQL> desc test;

  Name Type Nullable Default Comments

  ------- ------------ -------- ------- --------

  COUNTRY VARCHAR2(20) Y

  CITY VARCHAR2(20) Y

  SQL> select * from test;

  COUNTRY CITY

  -------------------- --------------------

  中国 台北

  中国 香港

  中国 上海

  日本 东京

  日本 大阪

  要求得到如下结果集:

  ------- --------------------

  中国 台北,香港,上海

  日本 东京,大阪

  实际就是对字符实现一个聚合功能。

  下面就对几种经常提及的解决方案进行分析(有一个评测标准最高★★★★★):

  1.被集合字段范围小且固定型:

  灵活性★ 性能★★★★ 难度 ★

  这种方法的原理在于你已经知道CITY字段的值有几种,且还不算太多,如果太多这个SQL就会相当的长。看例子:

  SQL> select t.country,

  2 MAX(decode(t.city,'台北',t.city||',',NULL)) ||

  3 MAX(decode(t.city,'香港',t.city||',',NULL))||

  4 MAX(decode(t.city,'上海',t.city||',',NULL))||

  5 MAX(decode(t.city,'东京',t.city||',',NULL))||

  6 MAX(decode(t.city,'大阪',t.city||',',NULL))

  7 from test t GROUP BY t.country

  8 /

  COUNTRY MAX(DECODE(T.CITY,'台北',T.CIT

  -------------------- ------------------------------

  中国 台北,香港,上海,

  日本 东京,大阪,

  大家一看,估计就明白了(如果不明白,好好补习MAX DECODE和分组)。这种方法无愧为最笨的方法,但是对某些应用来说,最有效的方法也许就是它。

  2.固定表固定字段函数法:

  灵活性★★ 性能★★★★ 难度 ★★

  此法必须预先知道是哪个表,也就是说一个表就得写一个函数,不过方法1的一个取值就要便捷多了。在大多数应用中,也不会存在大量这种合并字符串的需求。废话完毕,看下面:

  定义一个函数:

  create or replace function str_list( str_in in varchar2 )

  --分类字段

  return varchar2 is

  str_list varchar2(4000) default null;

  --连接后字符串

  str varchar2(20) default null;

  --连接符号

  begin

  for x in ( select TEST.CITY from TEST

  where TEST.COUNTRY = str_in ) loop

  str_list := str_list || str || to_char(x.city);

  str := ', ';

  end loop;

  return str_list;

  end;

  使用:

  SQL> select DISTINCT(T.country),

  list_func1(t.country) from test t;

  COUNTRY LIST_FUNC1(T.COUNTRY)

  -------------------- ----------------

  中国 台北, 香港, 上海

  日本 东京, 大阪

  SQL> select t.country,str_list(t.country)

  from test t GROUP BY t.country;

  COUNTRY STR_LIST(T.COUNTRY)

  -------------------- -----------------------

  中国 台北, 香港, 上海

  日本 东京, 大阪

  这个时候,使用分组和求唯一都可以满足要求。它的原理就是,根据唯一的分组字段country,在函数里面再次查询该字段对应的所有被合并列,使用PL/SQL将其合并输出。

  3.灵活表函数法 灵活性★★★ 性能★★★ 难度 ★★★

  该方法是在方法2的基础上,使用动态SQL,将表名和字段名称传入,从而达到灵活的目的。

  create or replace function str_list2

  ( key_name in varchar2,

  key in varchar2,

  coname in varchar2,

  tname in varchar2 )

  return varchar2

  as

  type rc is ref cursor;

  str varchar2(4000);

  sep varchar2(2);

  val varchar2(4000);

  cur rc;

  begin

  open cur for 'select '||coname||'

  from '|| tname || '

  where ' || key_name || ' = :x '

  using key;

  loop

  fetch cur into val;

  exit when cur%notfound;

  str := str || sep || val;

  sep := ', ';

  end loop;

  close cur;

  return str;

  end;

  SQL> select test.country,

  2 str_list2('COUNTRY',

  test.country, 'CITY', 'TEST') emplist

  3 from test

  4 group by test.country

  5 /

  COUNTRY EMPLIST

  -------------------- -----------------

  中国 台北, 香港, 上海

  日本 东京, 大阪

  4.一条SQL语法:

  灵活性★★★★ 性能★★ 难度 ★★★★

  一条SQL的法则是某位大师提出的,大家曾经在某个时期都乐此不彼的寻求各种的问题一条SQL法,但是大师的意思似乎被曲解,很多性能差,可读性差,灵活差的SQL都是这个原则产物,所谓画虎不成反成犬类。不过,解决问题始终是第一原则,这里还是给出一个比较有代表性的一条SQL方法。

  SELECT country,max(substr(city,2)) city

  FROM

  (SELECT country,sys_connect_by_path(city,',') city

  FROM

  (SELECT country,city,country||

  rn rchild,country||(rn-1) rfather

  FROM

  (SELECT test.country ,test.city,row_number() over

  (PARTITION BY test.country ORDER BY

  test.city) rn

  FROM test))

  CONNECT BY PRIOR rchild=rfather

  START WITH rfather LIKE '%0')

  GROUP BY country;

  下面分步解析,有4个FROM,就有4次结果集的操作。

  step 1 给记录加上序号rn

  SQL> SELECT test.country ,test.city,row_number() over

  (PARTITION BY test.country ORDER

  BY test.city) rn

  2 FROM test

  3 /

  COUNTRY CITY RN

  -------------------- -------------------- ----------

  日本 大阪 1

  日本 东京 2

  中国 上海 1

  中国 台北 2

  中国 香港 3

  step 2 创造子节点父节点:

  SQL> SELECT country,city,country||

  rn rchild,country||(rn-1) rfather

  2 FROM

  3 (SELECT test.country ,

  test.city,row_number() over

  (PARTITION BY test.country ORDER

  BY test.city) rn

  4 FROM test)

  5 /

  日本 大阪 日本1 日本0

  日本 东京 日本2 日本1

  中国 上海 中国1 中国0

  中国 台北 中国2 中国1

  中国 香港 中国3 中国2

  step 3 利用sys_connect_by_path生成结果集:

  SELECT country,sys_connect_by_path(city,',') city

  FROM

  (SELECT country,city,country||

  rn rchild,country||(rn-1) rfather

  FROM

  (SELECT test.country ,test.city,row_number()

  over (PARTITION BY test.country ORDER BY

  test.city) rn

  FROM test))

  CONNECT BY PRIOR rchild=rfather START WITH rfather LIKE '%0'

  日本 ,大阪

  日本 ,大阪,东京

  中国 ,上海

  中国 ,上海,台北

  中国 ,上海,台北,香港

  step 4 最终步骤,筛选结果集合:

  SQL> SELECT country,max(substr(city,2)) city

  2 FROM

  3 (SELECT country,sys_connect_by_path(city,',') city

  4 FROM

  5 (SELECT country,city,country||rn rchild,country||

  (rn-1) rfather

  6 FROM

  7 (SELECT test.country ,test.city,row_number()

  over (PARTITION BY test.country ORDER

  BY test.city) rn

  8 FROM test))

  9 CONNECT BY PRIOR rchild=rfather START WITH rfather LIKE '%0')

  10 GROUP BY country;

  COUNTRY CITY

  -------------------- -------

  中国 上海,台北,香港

  日本 大阪,东京

  5.自定义聚合函数:

  灵活性★★★★★ 性能★★★★★ 难度 ★★★★★

  最后一个方法是我认为“王道”的方法,自定义聚合函数。就如何我在本开始说的,为啥oracle没有这种聚合函数呢?我也不知道,但Oracle提供了聚合函数的API可以让我方便的自己定义聚合函数。

  下面给出一个简单的例子:

  SQL> SELECT t.country,strcat(t.city)

  FROM test t GROUP BY t.country;

  COUNTRY STRCAT(T.CITY)

  -------------------- ------------------

  日本 东京,大阪

  中国 台北,香港,上海

  简单吧,和官方的函数一样的便捷高效。

  函数:

  CREATE OR REPLACE FUNCTION strcat(input varchar2 )

  RETURN varchar2

  PARALLEL_ENABLE AGGREGATE USING strcat_type;

  TYPE:

  create or replace type strcat_type as object (

  cat_string varchar2(4000),

  static function ODCIAggregateInitialize

  (cs_ctx In Out strcat_type) return number,

  member function ODCIAggregateIterate

  (self In Out strcat_type,value in varchar2) return

  number,

  member function ODCIAggregateMerge

  (self In Out strcat_type,ctx2 In Out strcat_type)

  return number,

  member function ODCIAggregateTerminate

  (self In Out strcat_type,returnValue Out

  varchar2,flags in number) return number

  )

  6.待发掘:

  总结,合并字符串还有更多的方法希望大家能发掘,本文的目的主要是抛砖引玉,如果有新的发现我会继续更新方法。需要注意的问题是,本文采用varchar2为例子,所以长度有限制,Oracle的版本对方法的实现也影响。

分享到:
评论

相关推荐

    Oracle多行记录合并

    Oracle多行记录合并/连接/聚合字符串的几种方法

    Oracle 多行记录合并_连接_聚合字符串的几种方法_oracle_脚本之家1

    1.被集合字段范围小且固定型 灵活性 性能 难度 2.固定表固定字段函数法 灵活性 性能 难度 3.灵活表函数法 灵活性 性能 难度 4.一条SQL法 灵活性

    Oracle字段转字符串/多行记录合并/连接/聚合字符串的几种方法

    NULL 博文链接:https://czjxdm.iteye.com/blog/466948

    Oracle 多行记录合并/连接/聚合字符串的几种方法

    怎么合并多行记录的字符串,一直是oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结。

    oracle远程连接服务器出现 ORA-12170 TNS:连接超时 解决办法

    您可能感兴趣的文章:常用的Oracle doc命令(收藏)Oracle 多行记录合并/连接/聚合字符串的几种方法Oracle中字符串连接的实现方法php连接oracle数据库及查询数据的方法plsql连接oracle数据库报ora 12154错

    最全的oracle常用命令大全.txt

    Oracle数据库有哪几种启动方式 说明: 有以下几种启动方式: 1、startup nomount 非安装启动,这种方式启动下可执行:重建控制文件、重建数据库 读取init.ora文件,启动instance,即启动SGA和后台进程,这种启动...

    orcale常用命令

    Oracle数据库有哪几种启动方式 说明: 有以下几种启动方式: 1、startup nomount 非安装启动,这种方式启动下可执行:重建控制文件、重建数据库 读取init.ora文件,启动instance,即启动SGA和后台进程,这种启动...

    程序员的SQL金典6-8

     11.5 计算字符在字符串中出现的次数  11.6 去除最高分、最低分  11.6.1 去除所有最低、最高值  11.6.2 只去除一个最低、最高值  11.7 与日期相关的应用  11.7.1 计算销售确认日和制单日之间相差的天数  11.7...

    程序员的SQL金典7-8

     11.5 计算字符在字符串中出现的次数  11.6 去除最高分、最低分  11.6.1 去除所有最低、最高值  11.6.2 只去除一个最低、最高值  11.7 与日期相关的应用  11.7.1 计算销售确认日和制单日之间相差的天数  11.7...

    程序员的SQL金典3-8

     11.5 计算字符在字符串中出现的次数  11.6 去除最高分、最低分  11.6.1 去除所有最低、最高值  11.6.2 只去除一个最低、最高值  11.7 与日期相关的应用  11.7.1 计算销售确认日和制单日之间相差的天数  11.7...

    程序员的SQL金典4-8

     11.5 计算字符在字符串中出现的次数  11.6 去除最高分、最低分  11.6.1 去除所有最低、最高值  11.6.2 只去除一个最低、最高值  11.7 与日期相关的应用  11.7.1 计算销售确认日和制单日之间相差的天数  11.7...

    程序员的SQL金典.rar

     11.5 计算字符在字符串中出现的次数  11.6 去除最高分、最低分  11.6.1 去除所有最低、最高值  11.6.2 只去除一个最低、最高值  11.7 与日期相关的应用  11.7.1 计算销售确认日和制单日之间相差的天数  11.7...

    php网络开发完全手册

    1.5 几种综合网络服务器系统的安装 14 1.5.1 XAMPP 14 1.5.2 WAMP 16 1.5.3 Appserv 17 1.5.4 EasyPHP 18 1.5.5 VertrigoServ 19 1.6 几种开发工具的介绍 20 1.6.1 Vi及Vim 20 1.6.2 Eclipse+PHPEclipse插件 21 ...

    功能超级强悍的文本编辑器 PilotEdit 14.3.0 + x64 中文多语免费版.zip

    >在所选文本的前后分别添加自定义的字符串 12. 正则表达式 >用正则表达式查找/替换多行文本 13. 脚本文件 >可以把常用的正则表达式定义在脚本中,直接运行脚本即可替换文字 14. 256位 AES加密/解密 >用PilotEdit直接...

    mysql数据库的基本操作语法

    空字符串“”是不等于null,0也不等于null create table temp( id int not null, name varchar(255) not null default ‘abc’, sex char null ) 上面的table加上了非空约束,也可以用alter来修改或增加非空约束 ...

    2009达内SQL学习笔记

    3、对列起别名:有直接起别名,加AS起别名,用双引号起别名等三种方法 (单引号,引起字符串;双引号,引起别名。起别名有符号,或者区分大小写时,必须用双引号) 多表查询时,可给表起别名。(给列起别名,列<空格...

    PL/SQL Developer8.04官网程序_keygen_汉化

     varchar2 用来存储变长的字符串,其使用语法为: varchar2[(size)] 其中size为可选,表示该字符串所能存储的最大长度。 在PL/SQL中声明变量与其他语言不太一样,它采用从右往左的方式声明,比如声明一个number类型...

    PLSQLDeveloper下载

    varchar2 用来存储变长的字符串,其使用语法为: varchar2[(size)] 其中size为可选,表示该字符串所能存储的最大长度。 在PL/SQL中声明变量与其他语言不太一样,它采用从右往左的方式声明,比如声明一个number类型...

Global site tag (gtag.js) - Google Analytics