为什么wm_concat在这里不起作用?

时间:2013-05-21 16:27:04

标签: sql oracle oracle11g string-aggregation wm-concat

我有这个问题:

(SELECT OBJECT_ID from cr_object_group_entries_vw where object_group_id IN
    (SELECT ITEM FROM TABLE(CR_FN_SPLIT_STRING('28,56',','))))

返回:

enter image description here

但是当我这样做时:

SELECT wm_concat(object_id) FROM
    (SELECT OBJECT_ID from cr_object_group_entries_vw where object_group_id IN
        (SELECT ITEM FROM TABLE(CR_FN_SPLIT_STRING('28,56',','))))

我得到一个空白的结果......我做错了什么?

4 个答案:

答案 0 :(得分:6)

您必须避免wm_concat功能,因为它没有记录,并在Oracle 8i时被发现为变通方法。

自从Tom Kyte here发现自定义聚合函数的旧方法时,有一些新的解决方法,如下面的示例所示。

所有这些都转载于this SQL Fiddle

解决方法1 - LISTAGG功能,适用于11g:

select listagg(object_id,',') within group (order by rownum) id_string
from cr_object_group_entries_vw

解决方法2 - SYS_CONNECT_BY_PATH,自10g起作用:

select id_string from (
  select rn, substr(sys_connect_by_path(object_id, ','),2) id_string
  from (select object_id, rownum rn from cr_object_group_entries_vw)
  start with rn = 1
  connect by prior rn + 1 = rn
  order by rn desc
)
where rownum = 1

解决方法3 - XMLAGG,自10g起作用:

select replace(
         replace(
           replace(
             xmlagg(xmlelement("x",object_id)).getStringVal(),
             '</x><x>',
             ','
           ),
           '<x>',
           ''
         ),
         '</x>',
         ''
       ) id_string
from cr_object_group_entries_vw

P.S。我不确切地知道引入了哪个Oracle版本sys_connect_by_pathxmlagg,但两者在10.2.0.4.0上运行良好

答案 1 :(得分:4)

如果您使用11g,请尝试LISTAGG而不是wm_concat作为初学者。

答案 2 :(得分:3)

我刚看到有关wm_concat的帖子,并想过分享一些信息。

任何一直依赖wm_concat功能的应用程序在升级到12c后将无效。因为,它已从最新的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

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

有关其他解决方案,请参阅 Oracle String Aggregation Techniques

答案 3 :(得分:2)

你似乎没有做错任何事。使用虚拟表函数返回您显示的数据,wm_concat为我工作:

select wm_concat(object_id) from
    (select object_id from cr_object_group_entries_vw where object_group_id in
        (select item from table(cr_fn_split_string('28,56',','))))
/

WM_CONCAT(OBJECT_ID)                                                           
--------------------------------------------------------------------------------
36,1,11,121,13,14,17,18,2,24,3,32,33,34,35,36,37,38,39,40,42,43,44,6,7,8,81      

您已将问题标记为[11g];正如@beherenow所说,如果可以的话,你应该使用受支持的lisgagg覆盖不受支持的wm_concat,尽管它只能从11gR2获得,我认为:

select listagg(object_id, ',') within group (order by object_id)
from cr_object_group_entries_vw
where object_group_id in
    (select item from table(cr_fn_split_string('28,56',',')))
/

LISTAGG(OBJECT_ID,',')WITHINGROUP(ORDERBYOBJECT_ID)
---------------------------------------------------------------------------
1,11,121,13,14,17,18,2,24,3,32,33,34,35,36,36,37,38,39,40,42,43,44,6,7,8,81

SQL Fiddle(仅适用于listagg,因为它不支持wm_concat - 也许您的实例也不支持,但它应该出错?)