关于oracle中的wmsys.wm_concat中的使用问题

 转:http://blog.csdn.net/pengdingxu10/article/details/46438567

    这两天在项目中遇到了一个问题,就是系统中使用了wmsys.wm_concat引发的相关问题,PM也提议不要使用,原因有下:

    1.该函数不是oracle公开的系统函数,它的用户是wmsys,而不是sys或者system,oracle很有可能在版本升级或者补丁的时候取消或者修改这个函数甚至用户,这种变化oracle是不会公开的。所有可能会由于这个变化而导致异常。

    2.大量使用这个函数也会导致临时表空间爆满,这是因为在10.2.0.5中,使用wmsys.wm_concat返回的结果格式是CLOB,CLOB占用的临时表空间只有在连接释放后才会释放,部分通过连接池连接数据库的长连接很有可能导致CLOB占用临时表空间不断累积增大,会导致临时表空间爆满的故障

    3.如果是在程序中大量使用这个函数的话会引起enq:TT的锁,可能会导致某些对象被锁。

    解决办法:

    官方文档给了建议,可以参考该函数自己建立一个函数实现相同的行列转换功能。


    然后我上网找了一些资料,http://www.eygle.com/archives/2012/10/wmsys_wm_concat.html

    确实可以实现跟wmsys.wm_concat一样的功能,下面是这篇文章的实现

    create or replace TYPE en_concat_im

       AUTHID CURRENT_USER AS OBJECT
       (
         CURR_STR VARCHAR2(32767),
         STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT en_concat_im) RETURN NUMBER,
         MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT en_concat_im,
           P1 IN VARCHAR2) RETURN NUMBER,
         MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN en_concat_im,
             RETURNVALUE OUT VARCHAR2,
            FLAGS IN NUMBER)
          RETURN NUMBER,
        MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT en_concat_im,
        SCTX2 IN  en_concat_im) RETURN NUMBER
     );
     
    create or replace TYPE BODY en_concat_im
       IS
         STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT en_concat_im)
         RETURN NUMBER
         IS
         BEGIN
        SCTX := en_concat_im(NULL) ;
        RETURN ODCICONST.SUCCESS;
       END;
       MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT en_concat_im,
              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 en_concat_im,
             RETURNVALUE OUT VARCHAR2,
             FLAGS IN NUMBER)
       RETURN NUMBER
        IS
         BEGIN
       RETURNVALUE := CURR_STR ;
        RETURN ODCICONST.SUCCESS;
        END;
         MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT en_concat_im,
        SCTX2 IN en_concat_im)
         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 en_concat(P1 VARCHAR2) RETURN VARCHAR2 AGGREGATE USING en_concat_im ;

    然后运行测试:select en_concat(username) from dba_users;   ok可以实现行列转换。具体的性能分析可以浏览该网址的文章


    但是我在运行的时候出了个问题,就是查询的表数据量比较大的时候会报:Oracle ORA-06502: PL/SQL: 数字或值错误 : 字符串缓冲区太小这个错误

    我当时不明白什么原因,后面百度了一下这个原因,看到了一篇文章:http://bbs.csdn.net/topics/360059765

    楼主的问题:

    使用wmsys.wm_concat多列合成一列遇到问题
    ORA-22813: 操作数值超出系统的限制

    往下看了之后对比了一下这个问题的解决办法,原理跟上面一样,也是自定义type来实现,但是有一个不同点的就是,上面的实现我标注的地方,返回的是varchar2类型的

    在看看这篇文章里面的实现:

    CREATE  OR  REPLACE  TYPE zh_concat_im
    AUTHID  CURRENT_USER  AS  OBJECT
    (
       CURR_STR clob,
       STATIC  FUNCTION  ODCIAGGREGATEINITIALIZE(SCTX  IN  OUT  zh_concat_im)  RETURN  NUMBER,
       MEMBER  FUNCTION  ODCIAGGREGATEITERATE(SELF  IN  OUT  zh_concat_im,
       P1  IN  VARCHAR2)  RETURN  NUMBER,
       MEMBER  FUNCTION  ODCIAGGREGATETERMINATE(SELF  IN  zh_concat_im,
       RETURNVALUE OUT clob,
       FLAGS  IN  NUMBER)
       RETURN  NUMBER,
       MEMBER  FUNCTION  ODCIAGGREGATEMERGE(SELF  IN  OUT  zh_concat_im,
       SCTX2  IN  zh_concat_im)  RETURN  NUMBER
    );
     
    CREATE  OR  REPLACE  TYPE BODY zh_concat_im
    IS
       STATIC  FUNCTION  ODCIAGGREGATEINITIALIZE(SCTX  IN  OUT  zh_concat_im)
       RETURN  NUMBER
       IS
       BEGIN
       SCTX := zh_concat_im( NULL ) ;
       RETURN  ODCICONST.SUCCESS;
       END ;
       MEMBER  FUNCTION  ODCIAGGREGATEITERATE(SELF  IN  OUT  zh_concat_im,
     
       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  zh_concat_im,
       RETURNVALUE OUT clob,
       FLAGS  IN  NUMBER)
       RETURN  NUMBER
       IS
       BEGIN
       RETURNVALUE := CURR_STR ;
       RETURN  ODCICONST.SUCCESS;
       END ;
       MEMBER  FUNCTION  ODCIAGGREGATEMERGE(SELF  IN  OUT  zh_concat_im,
       SCTX2  IN  zh_concat_im)
       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  zh_concat(P1 VARCHAR2)
    RETURN  clob AGGREGATE USING zh_concat_im ;

    这个定义的的clob类型,所有这个函数可以实现,没有出现了Oracle ORA-06502:这个错误,顿时恍然啊。

    至于clob这个类型跟varchar2各位就查资料看看了,但是目前我还是有点不明白,这样实现也是用clob这个类型,会不会也会临时表空间增大,目前没有测试过。

    以上就是这两天查资料看到的这些,有错的地方希望指出来了;我oracle也不是很熟哈!!!如果哪位大神能更好的说明的那就更好了。

    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值