8

通常,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

4 回答 4

16

You might want to use LISTAGG.

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

Output:

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

SQLFiddle

UPDATE If you need to get distinct text values in a list

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

于 2013-05-28T08:11:18.350 回答
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
于 2014-07-03T12:51:44.497 回答
4

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

请勿使用WM_CONCAT,因为它是一个未记录的功能,并且已从最新的12c 版本中删除。任何一直依赖wm_concat功能的应用程序一旦升级到12c. 请参阅为什么不在 Oracle 中使用 WM_CONCAT 函数?

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.

您将收到“<strong>invalid identifier”错误:

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

因此,没有必要依赖最新版本中不再提供的未记录功能。

有多种字符串聚合技术

  • 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 及以上的COLLECT功能

Tim Hall 的几个很好的例子

于 2015-05-16T07:20:52.463 回答
1

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

SELECT col_id, replace(wm_concat(col_text), ',', ' ') AS sentence
  FROM foo
 GROUP BY col_id;
于 2015-06-23T22:42:05.893 回答