【引言】 个人公众号之前的一篇文章曾经介绍过无效对象的问题。介绍到在数据库日常运维中,数据库中一些对象(如:Package、Procedure、Function、View、同义词等会失效,状态为INVALID,需定期检查数据库中存在哪些失效对象。自动失效的对象,一般会在下次调用的时候,会被重新编译,所以一般也不需要人工干预。对于存在异常的对象则需要手动重新编译;一个场景就是数据迁移也会导致无效对象的产生。
《Oracle番:啥是无效对象,出现时如何破?》
最近的一次oracle库大版本升级,版本从11g升级至19c;按照《Oracle番:啥是无效对象,出现时如何破?》,升级至19c后,执行如下utlrp.sql脚本编译了数据库失效对象后,还是有个应用账号报无效对象编辑失效的现象。 sql>@$ORACLE_HOME/rdbms/admin/utlrp.sql
报错信息如下: ORA-00904: “WM_CONCAT”: invalid identifie
经了解,wm_contact(column)函数从oracle10g开始使用,然而12C以上版本摒弃了wm_concat函数,导致不能识别"WM_CONCAT"函数。大家都知道,WM_CONCAT"可以实现oracle中字段的合并,wm_concat(列名)函数,能把指定的列的值,按照group by 中指定的分隔方法,用逗号拼接起来。通常用法如下例:
#通用用法 select id,wm_concat(test) result from test group by id;
#使用时记得用to_char()封装下 select id,to_char(wm_concat(test)) result from test group by id;
注意: 实际使用中,需用to_char(wm_concat())方式封装,方可正常调用。
至于为何oracle在12c的版本中抛弃不用wm_contact(column)? 个人这里大致推测下:应该和函数执行效率低有关,因为用过的朋友有切身体会,万行的查询合并,执行时间较长。另,wm_contact英文描述为undocumented,意味着随时可能发生变更;10.2.0.5上,其返回类型从varchar2变为了clob,12c后续版本,直接就取消了此函数。用到此函数的数据库发生大版本升级,如本人的11g升级19c,就是一大坑,因升级后如不注意,应用在进行功能性测试时,肯定出问题。
后续作者将继续研究下,也欢迎大家留言讨论oracle弃用wm_contact的原因。
本次升级,11g中版本对应的应用程序中使用了wm_contact该函数,升级后的19c没有此wmsys.wm_contact函数,故致使所以来的view和package报错,出现如下: ORA-00904: “WM_CONCAT”: invalid identifie
问题如何解决?
解决方案有三种: 方法1:19c中创建低版本的wm_contact函数; 方法2:19c中手动创建wm_contact函数; 方法3:使用其替代函数,listagg
方法1创建wm_contact函数 从原有低版本11g中copy相应的文件,在19c中执行创建wm_contact函数;具体如下: 从11g的 O R A C L E H O M E / r d b m s / a d m i n 目 录 下 拷 贝 o w m c t a b . p l b 、 o w m a g g r s . p l b 、 o w m a g g r b . p l b 三 个 文 件 至 19 c 的 ORACLE_HOME/rdbms/admin目录下拷贝owmctab.plb、owmaggrs.plb、owmaggrb.plb三个文件至19c的 ORACLEHOME/rdbms/admin目录下拷贝owmctab.plb、owmaggrs.plb、owmaggrb.plb三个文件至19c的ORACLE_HOME/rdbms/admin/目录下。然后依次执行owmctab.plb、owmaggrs.plb、owmaggrb.plb这三个文件。
查看owmctab.plb脚本内容,因owmctab.plb需要引用owmt9012.plb,而owmt9012.plb需要引用owmt9013.plb,故需要需要从11g中scp到19C中,如下共计5个文件。 owmctab.plb owmt9013.plb owmt9012.plb owmaggrs.plb owmaggrb.plb
19c中oracle环境下依次执行如下命令: SQL> @?/rdbms/admin/owmctab.plb SQL> @?/rdbms/admin/owmaggrs.plb SQL> @?/rdbms/admin/owmaggrb.plb
方法2:19c中手动创建wm_contact函数 参考如下链接: https://blog.csdn.net/alicewang99/article/details/89945252
创建wm_concat函数 –首先使用dba账号登录oracle数据库 –解锁wmsys用户 alter user wmsys account unlock;
–并为wmsys用户授权,可根据需要授权,不建议授权所有权限 grant all privileges to wmsys;
–如果不知道wmsys用户的密码,可以修改其密码 alter user wmsys identified by 123456;
–使用wmsys用户登录数据库 conn wmsys/123456
–在wmsys下创建可用的wm_concat函数,直接执行以下语句 –定义类型 CREATE OR REPLACE TYPE WM_CONCAT_IMPL 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 ); /
–定义类型body: 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 ; /
–创建完成,给其创建同义词及授权,以供其他用户能正常使用。 create public synonym WM_CONCAT_IMPL for wmsys.WM_CONCAT_IMPL / create public synonym wm_concat for wmsys.wm_concat /
grant execute on WM_CONCAT_IMPL to public / grant execute on wm_concat to public /
方法3:使用替代函数listagg 参考链接: https://blog.csdn.net/sinat_36257389/article/details/81004843 使用listagg函数代替 基本语法: SELECT T .DEPTNO, listagg (T.ENAME, ‘,’) WITHIN GROUP (ORDER BY T.ENAME) names FROM SCOTT.EMP T WHERE T.DEPTNO = ‘20’ GROUP BY T.DEPTNO
本文采用了方法1。
【结语】 1.个人进行oracle11g升级12c以上大版本的升级案例中,所遇到的第一个大坑;各位亲,请留意。 2.至于oracle官方为何弃用wm_contact函数,文中个人初步推断为该函数执行效率低的原因,后续具体原因,文章待定。 3.Oracle大版本后的升级,一定要谨慎再谨慎,充分做好应用测试。
【参考】 https://www.cnblogs.com/YuyuanNo1/p/7910714.html 【参考】 https://blog.csdn.net/sinat_36257389/article/details/81004843