2010-08-18 149 views
3

当我尝试在Oracle XE 10g上使用WMSYS.WM_CONCAT时,收到编译错误:ORA-00904: "WMSYS"."WM_CONCAT": invalid identifier。任何人都可以证实,这确实是由于XE缺乏这种(无证)功能吗?如果是这样,是否有XE启用它?在Oracle XE 10g中使用WMSYS.WM_CONCAT

回答

3

我已经找到了几个参考站点,但没有使它成功。我最终编写了自己的函数来处理并置。

CREATE or replace FUNCTION CONCAT_LIST(cur SYS_REFCURSOR, sep Varchar2) RETURN VARCHAR2 IS 
ret VARCHAR2(32000); 
tmp VARCHAR2(4000); 
BEGIN 
loop 
    fetch cur into tmp; 
    exit when cur%NOTFOUND; 
    if ret is null then 
     ret := tmp; 
    else 
     ret := ret || sep || tmp; 
    end if; 

end loop; 
RETURN ret; END;/ 

然后,它可以被称为

SELECT distinct CONCAT_LIST(CURSOR(SELECT id FROM test_table1), ',') test_table1 FROM dual

+1

谢谢,我为这个功能是否可以启用真的很好奇。我发现的最佳选择是用户定义的聚合函数:http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php。我将函数从string_agg重命名为wm_concat,因为我可以与拥有完整Oracle 10g的同事共享存储过程(文中给出的方法允许使用与真正的wm_concat相同的语法 - 只要您不使用完全限定wm_concat和wm_sys的脚本) – 2010-09-05 14:18:07

+0

这非常漂亮。我有几个大的查询,我正在使用这个函数。一旦我回到办公室,我会创建新的并检查性能。这让我好奇。谢谢! – RandyB 2010-09-05 14:42:46

+0

酷,我很乐意听到你的表现结果,当你完成。 – 2010-09-06 15:54:40

3

来源:link

自己刚刚创造这个功能:建议

CREATE OR REPLACE TYPE wm_concat_impl 
    AUTHID CURRENT_USER 
AS OBJECT (
    curr_str VARCHAR2 (32767), 
    STATIC FUNCTION odciaggregateinitialize (sctx IN OUT wm_concat_impl) 
     RETURN NUMBER, 
    MEMBER FUNCTION odciaggregateiterate (
     SELF IN OUT wm_concat_impl, 
     p1  IN  VARCHAR2 
    ) 
     RETURN NUMBER, 
    MEMBER FUNCTION odciaggregateterminate (
     SELF   IN  wm_concat_impl, 
     returnvalue OUT  VARCHAR2, 
     flags   IN  NUMBER 
    ) 
     RETURN NUMBER, 
    MEMBER FUNCTION odciaggregatemerge (
     SELF IN OUT wm_concat_impl, 
     sctx2 IN  wm_concat_impl 
    ) 
     RETURN NUMBER 
); 
/

CREATE OR REPLACE TYPE BODY wm_concat_impl 
IS 
    STATIC FUNCTION odciaggregateinitialize (sctx IN OUT wm_concat_impl) 
     RETURN NUMBER 
    IS 
    BEGIN 
     sctx := wm_concat_impl (NULL); 
     RETURN odciconst.success; 
    END; 
    MEMBER FUNCTION odciaggregateiterate (
     SELF IN OUT wm_concat_impl, 
     p1  IN  VARCHAR2 
    ) 
     RETURN NUMBER 
    IS 
    BEGIN 
     IF (curr_str IS NOT NULL) 
     THEN 
     curr_str := curr_str || ',' || p1; 
     ELSE 
     curr_str := p1; 
     END IF; 

     RETURN odciconst.success; 
    END; 
    MEMBER FUNCTION odciaggregateterminate (
     SELF   IN  wm_concat_impl, 
     returnvalue OUT  VARCHAR2, 
     flags   IN  NUMBER 
    ) 
     RETURN NUMBER 
    IS 
    BEGIN 
     returnvalue := curr_str; 
     RETURN odciconst.success; 
    END; 
    MEMBER FUNCTION odciaggregatemerge (
     SELF IN OUT wm_concat_impl, 
     sctx2 IN  wm_concat_impl 
    ) 
     RETURN NUMBER 
    IS 
    BEGIN 
     IF (sctx2.curr_str IS NOT NULL) 
     THEN 
     SELF.curr_str := SELF.curr_str || ',' || sctx2.curr_str; 
     END IF; 

     RETURN odciconst.success; 
    END; 
END; 
/

CREATE OR REPLACE FUNCTION wm_concat (p1 VARCHAR2) 
    RETURN VARCHAR2 
    AGGREGATE USING wm_concat_impl; 
/
2

不使用WM_CONCAT因为它是一个未公开的特性,它已经从12C版本中删除。见Why not use WM_CONCAT function in Oracle?

如果你是11gR2的及以上,使用LISTAGG

事先版本到11g其中LISTAGG不支持,你可以使用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.