【函数】wm_concat包的订制
【函数】wm_concat包的订制
1 BLOG文档结构图
2 前言部分
2.1 导读和注意事项
各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~:
① 利用系统包创建WM_CONCAT函数(重点)
② ORA-00904: "wm_concat":invalid identifier错误解决
③ 订制自己的WM_CONCAT函数
④ listagg分析函数的使用
⑤ ORA-01489: result of string concatenation is too long的错误解决
Tips:
① 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和微信公众号(xiaomaimiaolhr)有同步更新。
② 文章中用到的所有代码,相关软件,相关资料请前往小麦苗的云盘下载(http://blog.itpub.net/26736162/viewspace-1624453/)。
③ 若网页文章代码格式有错乱,推荐使用360浏览器,也可以下载pdf格式的文档来查看,pdf文档下载地址:http://blog.itpub.net/26736162/viewspace-1624453/,另外itpub格式显示有问题,也可以去博客园地址阅读。
④ 本篇BLOG中命令的输出部分需要特别关注的地方我都用灰色背景和粉红色字体来表示,比如下边的例子中,thread 1的最大归档日志号为33,thread 2的最大归档日志号为43是需要特别关注的地方;而命令一般使用黄色背景和红色字体标注;对代码或代码输出部分的注释一般采用蓝色字体表示。
List of Archived Logs in backup set 11 Thrd Seq Low SCN Low Time Next SCN Next Time ---- ------- ---------- ------------------- ---------- --------- 1 32 1621589 2015-05-29 11:09:52 1625242 2015-05-29 11:15:48 1 33 1625242 2015-05-29 11:15:48 1625293 2015-05-29 11:15:58 2 42 1613951 2015-05-29 10:41:18 1625245 2015-05-29 11:15:49 2 43 1625245 2015-05-29 11:15:49 1625253 2015-05-29 11:15:53 [ZHLHRDB1:root]:/>lsvg -o T_XLHRD_APP1_vg rootvg [ZHLHRDB1:root]:/> 00:27:22 SQL> alter tablespace idxtbs read write; ====》2097152*512/1024/1024/1024=1G |
本文如有错误或不完善的地方请大家多多指正,ITPUB留言或QQ皆可,您的批评指正是我写作的最大动力。
2.2 相关参考文章链接
行转列参考文章:http://blog.itpub.net/26736162/viewspace-1272538/
2.3 本文简介
WMSYS用户下的WM_CONCAT函数有很重要的用途,比如行转列(http://blog.itpub.net/26736162/viewspace-1272538/),但是该函数不稳定,在10G和11GR2上返回值不同,一个是字符串一个是CLOB,而且12C上已经摒弃了WM_CONCAT函数,但是我们很多程序员在程序中使用了该函数,若是系统升级就会导致程序出现错误,为了减轻程序员修改程序的工作量,只有创建这个WM_CONCAT函数来解决该问题。
一般情况下报错信息,ORA-00904: "wm_concat":invalid identifier,查询DBA_OBJECTS视图,也未发现wm_concat的相关信息。正常情况下查询,
SQL> SELECT * FROM DBA_OBJECTS WHERE OBJECT_NAME LIKE 'WM_CONCAT%';
应如下所示:
解决办法有2种,一种是采用Oracle本身的脚本来创建WM_CONCAT函数,一种是采用自己创建的函数来完成这个功能。
3 用Oracle自带脚本重建WMSYS用户的WMSYS.WM_CONCAT函数
运行如下脚本卸载WMSYS:
@$ORACLE_HOME/rdbms/admin/owmuinst.plb
运行如下脚本执行安装WMSYS:
@$ORACLE_HOME/rdbms/admin/owminst.plb
解锁wmsys用户:
ALTER USER WMSYS ACCOUNT UNLOCK;
4 自己创建wmsys
4.1 订制脚本
若只是某个用户使用,那么我们可以不用刻意去创建wmsys用户,可以在当前用户下运行脚本,生成WM_CONCAT函数,为了和系统的函数名区别开来,我们也可以修改函数名称,订制自己的脚本。
4.1.1 无分隔符,返回CLOB
创建函数的脚本如下:
CREATE OR REPLACE TYPE WM_CONCAT_IMPL_CLOB_NULL_LHR AUTHID CURRENT_USER AS OBJECT ( CURR_STR CLOB, STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT WM_CONCAT_IMPL_CLOB_NULL_LHR) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL_CLOB_NULL_LHR, P1 IN CLOB) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN WM_CONCAT_IMPL_CLOB_NULL_LHR, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL_CLOB_NULL_LHR, SCTX2 IN WM_CONCAT_IMPL_CLOB_NULL_LHR) RETURN NUMBER ); / CREATE OR REPLACE TYPE BODY WM_CONCAT_IMPL_CLOB_NULL_LHR IS STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT WM_CONCAT_IMPL_CLOB_NULL_LHR) RETURN NUMBER IS BEGIN SCTX := WM_CONCAT_IMPL_CLOB_NULL_LHR(NULL); RETURN ODCICONST.SUCCESS; END; MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL_CLOB_NULL_LHR, P1 IN CLOB) 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_CLOB_NULL_LHR, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER IS BEGIN RETURNVALUE := CURR_STR; RETURN ODCICONST.SUCCESS; END; MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL_CLOB_NULL_LHR, SCTX2 IN WM_CONCAT_IMPL_CLOB_NULL_LHR) 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_CLOB_NULL_LHR(P1 VARCHAR2) RETURN CLOB AGGREGATE USING WM_CONCAT_IMPL_CLOB_NULL_LHR; /
CREATE PUBLIC SYNONYM WM_CONCAT_CLOB_NULL_LHR FOR WM_CONCAT_CLOB_NULL_LHR; GRANT EXECUTE ON WM_CONCAT_CLOB_NULL_LHR TO PUBLIC; |
测试案例,注意函数的返回值是无分隔符的CLOB,在PL/SQL中注意使用to_char进行转换:
SYS@lhrdb21> SELECT D.USER_ID FROM DBA_USERS D WHERE D.USER_ID IN (0, 5);
USER_ID ---------- 0 5
SYS@lhrdb21> SELECT WM_CONCAT_CLOB_NULL_LHR(D.USER_ID) FROM DBA_USERS D WHERE D.USER_ID IN (0, 5);
WM_CONCAT_CLOB_LHR_NULL(D.USER_ID) -------------------------------------------------------------------------------- 05
SYS@lhrdb21> |
4.1.2 逗号分隔符,返回CLOB
创建函数的脚本如下:
CREATE OR REPLACE TYPE WM_CONCAT_IMPL_CLOB_LHR AUTHID CURRENT_USER AS OBJECT ( CURR_STR CLOB, STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT WM_CONCAT_IMPL_CLOB_LHR) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL_CLOB_LHR, P1 IN CLOB) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN WM_CONCAT_IMPL_CLOB_LHR, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL_CLOB_LHR, SCTX2 IN WM_CONCAT_IMPL_CLOB_LHR) RETURN NUMBER ); / CREATE OR REPLACE TYPE BODY WM_CONCAT_IMPL_CLOB_LHR IS STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT WM_CONCAT_IMPL_CLOB_LHR) RETURN NUMBER IS BEGIN SCTX := WM_CONCAT_IMPL_CLOB_LHR(NULL); RETURN ODCICONST.SUCCESS; END; MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL_CLOB_LHR, P1 IN CLOB) 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_CLOB_LHR, RETURNVALUE OUT CLOB, FLAGS IN NUMBER) RETURN NUMBER IS BEGIN RETURNVALUE := CURR_STR; RETURN ODCICONST.SUCCESS; END; MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL_CLOB_LHR, SCTX2 IN WM_CONCAT_IMPL_CLOB_LHR) 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_CLOB_LHR(P1 VARCHAR2) RETURN CLOB AGGREGATE USING WM_CONCAT_IMPL_CLOB_LHR; /
CREATE PUBLIC SYNONYM WM_CONCAT_CLOB_LHR FOR WM_CONCAT_CLOB_LHR; GRANT EXECUTE ON WM_CONCAT_CLOB_LHR TO PUBLIC; |
测试案例,注意函数的返回值是以逗号为分隔符的CLOB,在PL/SQL中注意使用to_char进行转换:
SYS@lhrdb21> SELECT D.USER_ID FROM DBA_USERS D WHERE D.USER_ID IN (0, 5);
USER_ID ---------- 0 5 SYS@lhrdb21> SELECT WM_CONCAT_CLOB_LHR(D.USER_ID) FROM DBA_USERS D WHERE D.USER_ID IN (0, 5);
WM_CONCAT_LHR(D.USER_ID) -------------------------------------------------------------------------------- 0,5 |
4.1.3 逗号分隔符,返回字符串
创建函数的脚本如下:
CREATE OR REPLACE TYPE WM_CONCAT_IMPL_STRINGS_LHR AUTHID CURRENT_USER AS OBJECT ( CURR_STR VARCHAR2(32767), STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT WM_CONCAT_IMPL_STRINGS_LHR) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL_STRINGS_LHR, P1 IN VARCHAR2) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN WM_CONCAT_IMPL_STRINGS_LHR, RETURNVALUE OUT VARCHAR2, FLAGS IN NUMBER) RETURN NUMBER, MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL_STRINGS_LHR, SCTX2 IN WM_CONCAT_IMPL_STRINGS_LHR) RETURN NUMBER ); / CREATE OR REPLACE TYPE BODY WM_CONCAT_IMPL_STRINGS_LHR IS STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT WM_CONCAT_IMPL_STRINGS_LHR) RETURN NUMBER IS BEGIN SCTX := WM_CONCAT_IMPL_STRINGS_LHR(NULL); RETURN ODCICONST.SUCCESS; END; MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL_STRINGS_LHR, 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_STRINGS_LHR, 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_STRINGS_LHR, SCTX2 IN WM_CONCAT_IMPL_STRINGS_LHR) 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_STRINGS_LHR(P1 VARCHAR2) RETURN VARCHAR2 AGGREGATE USING WM_CONCAT_IMPL_STRINGS_LHR; /
CREATE PUBLIC SYNONYM WM_CONCAT_STRINGS_LHR FOR WM_CONCAT_STRINGS_LHR; GRANT EXECUTE ON WM_CONCAT_STRINGS_LHR TO PUBLIC; |
测试案例,注意函数的返回值是以逗号为分隔符的字符串:
SYS@lhrdb21> SELECT D.USER_ID FROM DBA_USERS D WHERE D.USER_ID IN (0, 5);
USER_ID ---------- 0 5
SYS@lhrdb21> SELECT WM_CONCAT_STRINGS_LHR(D.USER_ID) FROM DBA_USERS D WHERE D.USER_ID IN (0, 5);
WM_CONCAT_STRINGS_LHR(D.USER_ID) --------------------------------------------------- 0,5 |
5 listagg的使用
这是一个Oracle的列转行函数:LISTAGG()
with temp as(
select 'China' nation ,'Guangzhou' city from dual union all
select 'China' nation ,'Shanghai' city from dual union all
select 'China' nation ,'Beijing' city from dual union all
select 'USA' nation ,'New York' city from dual union all
select 'USA' nation ,'Bostom' city from dual union all
select 'USA' nation ,'Bostom' city from dual union all
select 'Japan' nation ,'Tokyo' city from dual
)
select nation,listagg(city,',') within GROUP (order by city)
from temp
group by nation;
但是如果聚合的内容太多就会报ORA-01489: result of string concatenation is too long的错误,这个时候可以从业务的角度去修改SQL,也可以使用WM_CONCAT函数返回CLOB类型来解决这个问题。如下聚合DBA_OBJECTS中的OBJECT_NAME就会报错:
SELECT LISTAGG(OBJECT_NAME, ',') WITHIN GROUP(ORDER BY OBJECT_NAME)
FROM DBA_OBJECTS D;
报错:ORA-01489: result of string concatenation is too long
解决:可以用WM_CONCAT返回CLOB类型即可。SELECT WM_CONCAT_CLOB_LHR(D.OBJECT_NAME) FROM DBA_OBJECTS D;
注意:有关WM_CONCAT函数返回CLOB类型的性能问题,我们本篇文章不讨论,聚合的内容多了,自然就慢,到底是避免出ORA-01489错误还是要结果,这个还得根据自己的情况权衡决定,比如有的系统tmp很大,随便用,那作为开发人员,估计才不会考虑这么多的,不管白猫黑猫,抓住老鼠就是好猫。
About Me
............................................................................................................................... ● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用 ● 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新 ● 本文itpub地址:http://blog.itpub.net/26736162/viewspace-2124931/ ● 本文博客园地址:http://www.cnblogs.com/lhrbest/p/5869463.html ● 本文pdf版:http://yunpan.cn/cdEQedhCs2kFz (提取码:ed9b) ● 小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/ ● QQ群:230161599 微信群:私聊 ● 联系我请加QQ好友(642808185),注明添加缘由 ● 于 2016-09-13 09:00~ 2016-09-13 11:30 在中行完成 ● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解! ● 【版权所有,文章允许转载,但须以链接方式注明源地址,否则追究法律责任】 ............................................................................................................................... 手机长按下图识别二维码或微信客户端扫描下边的二维码来关注小麦苗的微信公众号:xiaomaimiaolhr,免费学习最实用的数据库技术。 |
【函数】wm_concat包的订制的更多相关文章
- 订制rpm包到Centos7镜像中
本文以CentOS 7.4 最小化镜像(CentOS-7-x86_64-Minimal-1708.iso)为模版 要达到的目的: 1.订制所需的rpm软件包集成到iso文件中 2.制作完成的ISO全自 ...
- oracle PL/SQL(procedure language/SQL)程序设计之函数+过程+包
匿名PL/SQL块回顾 DECLARE (可选) 定义在PL/SQL块中要使用的对象BEGIN (必须) 执行语句EXCEPTION (可选) 错误处理语句END; (必须)匿名块( ...
- oracle PL/SQL(procedure language/SQL)程序设计之函数+过程+包(转)
匿名PL/SQL块回顾 DECLARE (可选) 定义在PL/SQL块中要使用的对象 BEGIN (必须) 执行语句 EXCEPTION (可选) 错误处理语句 END; (必 ...
- JEasyPoi 2.1.4 (Jeecg订制) 版本发布,Excel 和 Word 简易工具类
JEasyPoi 2.1.4 (jeecg订制)版本发布,EasyPoi Excel 和 Word 简易工具类 easypoi 功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 ...
- Oracle中如何导出存储过程、函数、包和触发器的定义语句?如何导出表的结构?如何导出索引的创建语句?
Oracle中如何导出存储过程.函数.包和触发器的定义语句?如何导出表的结构?如何导出索引的创建语句? QQ群里有人问:如何导出一个用户下的存储过程? 麦苗答:方法有多种,可以使用DBMS_MET ...
- 订制EditText光标
订制EditText光标 设置背景android:background="@null" 设置光标样式:android:textCursorDrawable="@drawa ...
- Hadoop源码学习笔记(2) ——进入main函数打印包信息
Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...
- XMPP键盘订制实现图文混排
在现阶段的通信服务中,各种标准都有,因此会出现无法实现相互连通,而XMPP(Extensible Message and presence Protocol)协议的出现,实现了整个及时通信服务协议的互 ...
- 五.dbms_transaction(用于在过程,函数,和包中执行SQL事务处理语句.)
1.概述 作用:用于在过程,函数,和包中执行SQL事务处理语句. 2.包的组成 1).read_only说明:用于开始只读事务,其作用与SQL语句SET TRANSACTION READ ONLY完全 ...
随机推荐
- JDBC操作数据库工具类(使用阿里Druid原生API创建数据源)
1.数据库配置类 package com.zdlt.auth.api.common.druid; import java.util.Properties; import static com.alib ...
- Django入门4 数据库设计
创建mxonline虚拟环境 C:\Users\ws>mkvirtualenv mxonline (mxonline) D:\python\djangostart>pip install ...
- mysql5.7的主从切换
mysql5.7的主从切换 主库: master 10.11.0.211 从库: slave 10.11.0.210 目标:主从切换,将slave切换为master,master切换为slave 一. ...
- 动手制作 java版本切换 多版本JDK安装 windows JDK版本 切换
[参考]windows下JDK版本之间的切换 1.下载各版本安装包,指定安装位置顺序安装 2.删除注册表,文件和环境变量 文件: C:\Windows\System32 下java相关文件如 jav ...
- Superset配置impala数据源
1.安装impyla pip install impyla 2.在superset页面配置如下,此时impala是有kerberos认证的 impala://xxxx:xx/default?auth_ ...
- Linux 修改用户的JDK版本
1. vi .bash_profile 2.复制以下到bash_profile 文件,并将此文件里原来的JAVA_HOME和PATH删掉 JAVA_HOME=/java/jdk1..0_22 JRE ...
- Zabbix使用第三方API短信报警
之前试过邮件告警,微信告警.但是,对于一些企业的重要业务服务器,可能是存放在隔离的内网中的,无法正常连接外网.这个时候,就有必要考虑一下使用短信告警.以下这个其实还是需要服务器能够连接到外网的,但是我 ...
- snapde的批量文件数据过滤保存功能
一.snapde基本介绍 Snapde,一个专门为编辑超大型数据量CSV文件而设计的单机版电子表格软件:它运行的速度非常快,反应非常灵敏. 二.snapde批量数据筛选功能 如果想要对很多文件筛选出来 ...
- Java课堂笔记1
1. Java严格区分大小写 2. 一个源文件public主类名必须和文件名完全一致 3. 命名规则严格要求,字母.数字.下划线.美元符号$.下划线_组成,其中不能以数字开头,也不能使用Java的 ...
- Linux系统 关机/重启/用户切换/注销,用户管理(用户创建/修改,用户组增加/删除),Linux中 / 和 ~ 的区别
1.关机/重启命令 shutdown命令 shutdown -h now :立即关机 shutdown -h 1 :1分钟后关机 shutdown -r now :立即重启 shutdown -r 1 ...