【问题标题】:Using WMSYS.WM_CONCAT with Oracle XE 10g在 Oracle XE 10g 中使用 WMSYS.WM_CONCAT
【发布时间】:2011-03-31 15:18:42
【问题描述】:

当我尝试将 WMSYS.WM_CONCAT 与 Oracle XE 10g 一起使用时,我收到一个编译错误:ORA-00904: "WMSYS"."WM_CONCAT": invalid identifier。任何人都可以验证这确实是由于 XE 缺少此(未记录的)功能吗?如果是这样,是否有在 XE 中启用它?

【问题讨论】:

    标签: oracle oracle10g oracle-xe ora-00904 wm-concat


    【解决方案1】:

    建议不要使用 WM_CONCAT,因为它是一个未记录的功能,并且已从 12c 版本中删除。见Why not use WM_CONCAT function in Oracle?

    如果您使用的是 11gR2 及更高版本,请使用 LISTAGG

    对于不支持 LISTAGG11g 之前的版本,您可以使用 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.
    

    【讨论】:

      【解决方案2】:

      来源: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;
      /
      

      【讨论】:

        【解决方案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

        【讨论】:

        • 谢谢,我很好奇这个功能能不能开启。我找到的最佳替代方法是此处的用户定义聚合函数:oracle-base.com/articles/misc/StringAggregationTechniques.php。我将函数从 string_agg 重命名为 wm_concat 从那时起,我可以与拥有完整 oracle 10g 的同事共享存储过程(文章中给出的方法允许与真正的 wm_concat 使用相同的语法——只要你是不使用完全限定 wm_concat 和 wm_sys 的脚本)
        • 这很漂亮。我有几个正在使用此功能的大型查询。回到办公室后,我将创建新的并检查性能。这让我很好奇。谢谢!
        • 酷,我很想听听你完成后的表现结果。
        • 我对两个函数 CONCAT_LIST 和 STRING_AGG 进行了一些负载测试,发现我必须对我的函数进行一次修改。我忘了关闭光标,我很快就用完了允许的数量。进行更改后,我创建了一个查询,将一组 250 家商店分组到其相应类型。 CONCAT_LIST 在 2.68 秒内完成,来自 oracle-base 的 STRING_AGG 在 0.38 秒内完成,看起来更干净。我已经更改了必须引用这个新函数的几个查询。在这里,我以为我可以帮助你,而你最终帮助了我。谢谢!
        猜你喜欢
        • 1970-01-01
        • 2015-02-26
        • 1970-01-01
        • 2013-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-01
        • 2011-11-27
        相关资源
        最近更新 更多