更改Oracle 11gR2的WM_CONCAT函数的分隔符

时间:2013-05-28 08:07:13

标签: sql oracle function oracle11g

通常,WM_CONCAT是一个聚合函数,它返回表中用逗号分隔的值,就像这里一样。

假设我有一个像这样的表foo

col_id     | col_text


111        | This

111        | is

111        | a

111        | test.

如果我使用此查询:

SELECT CAST(WM_CONCAT(col_text) AS VARCHAR2(100)), col_id FROM foo

结果将是

This, is, a, test.

是否可以将分隔符(',')更改为'.'函数的'|'WM_CONCAT()等其他字符?

或创建一个可以像WM_CONCAT()一样执行的用户定义函数?

4 个答案:

答案 0 :(得分:14)

您可能想要使用LISTAGG

SELECT col_id, 
       LISTAGG(col_text, '|') WITHIN GROUP (ORDER BY col_text) text
  FROM table1
 GROUP BY col_id

输出:

| COL_ID |            TEXT |
----------------------------
|    111 | This|a|is|test. |

<强> SQLFiddle

更新如果您需要在列表中获取不同的文本值

SELECT col_id, 
       LISTAGG(col_text, '|')
         WITHIN GROUP (ORDER BY col_text) text
  FROM 
(
  SELECT DISTINCT col_id, col_text
    FROM table1
)
 GROUP BY col_id

<强> SQLFiddle

答案 1 :(得分:4)

LISTAGG的问题是它返回varchar2并且限制为4000字节

SELECT LISTAGG(LEVEL, CHR(10)) WITHIN GROUP (ORDER BY NULL)
  FROM Dual
CONNECT BY LEVEL < 2000

ORA-01489 Result of string concat is too large

我找到了一个解决方法,但看起来很丑陋而且变慢了

SELECT EXTRACT(XMLTYPE('<doc>' || XMLAGG(XMLTYPE('<ln>' || LEVEL || CHR(10) || '</ln>')).GetClobVal() || '</doc>'), '/doc/ln/text()').GetClobVal()
  FROM Dual
CONNECT BY LEVEL < 2000

答案 2 :(得分:4)

  

是否可以将分隔符(',')更改为其他字符,例如'。'或'|' WM_CONCAT()函数?

请勿使用WM_CONCAT,因为它是未记录的功能,并且已从最新的 12c版本 删除。任何一直依赖wm_concat功能的应用程序在升级到12c后将无法运行。见Why not use WM_CONCAT function in Oracle?

SQL> select banner from v$version where rownum = 1;

BANNER
----------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production

SQL> SELECT object_name
  2  FROM dba_objects
  3  WHERE owner='WMSYS'
  4  AND object_name LIKE 'WM\_%' ESCAPE '\';

OBJECT_NAME
----------------------------------------------------------------------------
WM_REPLICATION_INFO
WM_RDIFF
WM_PERIOD
WM_PERIOD
WM_OVERLAPS
WM_MEETS
WM_LESSTHAN
WM_LDIFF
WM_INTERSECTION
WM_INSTALLATION
WM_GREATERTHAN
WM_EVENTS_INFO
WM_ERROR
WM_ERROR
WM_EQUALS
WM_DDL_UTIL
WM_DDL_UTIL
WM_CONTAINS
WM_COMPRESS_BATCH_SIZES
WM_COMPRESSIBLE_TABLES

20 rows selected.

您将收到“无效标识符”错误:

SQL> SELECT banner FROM v$version;

BANNER
----------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
PL/SQL Release 12.1.0.1.0 - Production
CORE    12.1.0.1.0      Production
TNS for 64-bit Windows: Version 12.1.0.1.0 - Production
NLSRTL Version 12.1.0.1.0 - Production

SQL> SELECT deptno, wm_concat(ename) FROM emp;
SELECT deptno, wm_concat(ename) FROM emp
               *
ERROR at line 1:
ORA-00904: "WM_CONCAT": invalid identifier

因此,没有必要依赖未记录的功能,这在最新版本中不再可用。

有各种 string aggregation techniques

    11gR2及以上的
  • LISTAGG

例如,

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.
    9i及以上的
  • ROW_NUMBER() SYS_CONNECT_BY_PATH 功能

例如,

SELECT deptno,
       LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,','))
       KEEP (DENSE_RANK LAST ORDER BY curr),',') AS employees
FROM   (SELECT deptno,
               ename,
               ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) AS curr,
               ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS prev
        FROM   emp)
GROUP BY deptno
CONNECT BY prev = PRIOR curr AND deptno = PRIOR deptno
START WITH curr = 1;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.
  • AskTom中描述的用户定义的汇总功能 STRAGG
  • 收集 10g及以上的功能

蒂姆·霍尔here的几个很好的例子。

答案 3 :(得分:1)

以下在ORACLE 10.2.0.5.0数据库中为我工作:

SELECT col_id, replace(wm_concat(col_text), ',', ' ') AS sentence
  FROM foo
 GROUP BY col_id;