`
#rethink#
  • 浏览: 47464 次
  • 性别: 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 多行记录合并_连接_聚合字符串的几种方法_oracle_脚本之家1

    Oracle数据库在处理多行记录合并、连接和聚合字符串时,有多种方法,下面将详细介绍其中的几种常见技术。 1. 被集合字段范围小且固定型 这种方法适用于字段值有限且已知的情况。通过使用`DECODE`函数,我们可以为每...

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

    在Oracle数据库中,有时我们需要将多个字段值转换为单个字符串,或者将多行记录合并成一行,这在数据处理和报告生成时尤其常见。Oracle提供了多种方法来实现这一目标,包括使用内置函数、PL/SQL过程以及一些高级特性...

    Oracle多行记录合并

    本篇文章将详细介绍Oracle中实现多行记录合并的几种方法,包括使用SQL函数、集合操作以及自定义函数。 1. **使用SQL函数:** - **`LISTAGG()` 函数:** 这是Oracle 11g及以后版本引入的一个强大的聚合函数,专门...

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

    在Oracle数据库中,合并多行记录的字符串是一个常见的需求,特别是在报表或数据分析中。这个问题涉及到字符串的连接和聚合,使得多个记录的某个字段值能够整合到一行。在Oracle中,虽然没有内置的聚合函数直接支持...

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

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

    CLOB 字段类型报错 ORA-01704: 文字字符串过长的解决

    然而,当你尝试向CLOB字段插入数据时,如果超过了Oracle规定的最大限制,就会遇到“ORA-01704: 文字字符串过长”的错误。这个错误通常意味着你试图插入的字符串超过了Oracle数据库允许的最大长度,对于VARCHAR2类型...

    通过SQL语句实现行列转换的几种方法

    除此之外,还会涉及将多列或多行的数据合并为字符串,或将字符串拆分为多列或多行等操作。本文将重点探讨如何通过SQL语句实现这些转换,特别是将多行数据转换为单一字符串的情况。 #### 一、概述 行列转换可以分为...

    Sql Server脚本转Delphi语言格式字符串工具

    然而,SQL语句可能包含多行和特殊字符,这在Delphi中需要特别处理,例如使用三引号(''')包裹多行字符串,并对特殊字符进行转义。 转换过程大致如下: 1. **Sql转Delphi**:此工具会解析Sql Server脚本,将其中的...

    Oracle行列转换_总结

    除了上述两种基本的行列转换外,还有其他几种转换类型,包括多列到字符串、多行到字符串、字符串到多列以及字符串到多行的转换。这些转换通常涉及对数据进行重新组织或重组,以便于后续的处理或展示。 - **多列转换...

    Oracle 10g正则表达式函数

    Oracle 10g 正则表达式函数是 Oracle 数据库中的一种功能强大且灵活的字符串处理函数。它可以实现复杂的字符串匹配和提取功能,非常适合处理非结构化数据。 1. 元字符 在 Oracle 10g 正则表达式中,元字符是特殊的...

    Oracle函数列表速查

    Oracle函数是Oracle数据库中用于数据处理的重要工具,分为单行函数和组函数两种类型。单行函数处理单个数据行,对每一行都返回一个结果,而组函数则对多行进行聚合操作,如计数、求和等。 单行函数主要包括字符函数...

    oracle常用语法概述

    ### Oracle常用语法概述 Oracle是一种广泛使用的数据库管理系统,在企业级应用中非常常见。本文将详细介绍Oracle...以上这些函数可以帮助我们有效地处理和操作字符串数据,是Oracle数据库开发中不可或缺的一部分。

    ORACLE和SQL Server的语法区别

    - **Oracle:** Oracle使用`||`作为字符串连接运算符。 ```sql SELECT 'Hello' || 'World' AS Result; ``` - **SQL Server:** SQL Server使用`+`作为字符串连接运算符。 ```sql SELECT 'Hello' + 'World' AS ...

    Oracle函数大全实例

    本文将深入探讨Oracle中的几种主要函数类型:单行函数、多行函数以及分组函数,并给出相应的实例来帮助理解。 1. **单行函数** 单行函数在处理每一行数据时返回一个结果。它们分为字符函数、数字函数、日期函数和...

    Oracle100个常用函数.docx

    这些函数在Oracle数据库中非常实用,可以帮助用户处理各种字符串相关的操作,从而简化数据处理过程。通过上述示例,我们可以看到每个函数的具体应用方式及其返回的结果。这些知识点对于日常开发工作非常重要,掌握...

    02-oracle函数1

    接下来,我们详细探讨几种常见的Oracle函数: 1. **字符函数**: - `concat(string1, string2)`:连接两个字符串。 - `initcap(string)`:使字符串中每个单词的首字母大写。 - `lower(string)` / `upper(string)...

    Oracle与MySQL的几点区别

    然而,在某些情况下,Oracle还提供了更强大的字符串处理函数,如`INSTR`函数,可以用来查找特定子串在字符串中的位置。例如: ```sql -- Oracle示例:检查字符串中是否包含特定子串 SELECT column_name FROM table_...

Global site tag (gtag.js) - Google Analytics