【生产排故】oracle11g升19c之ORA-00904 WM_CONCAT invalid identifie排故

【引言】
个人公众号之前的一篇文章曾经介绍过无效对象的问题。介绍到在数据库日常运维中,数据库中一些对象(如: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/adminowmctab.plbowmaggrs.plbowmaggrb.plb19cORACLE_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

你可能感兴趣的:(oracle)