oracle中,wm_concat函数是一个聚合函数,和mysql中的group_concat函数类似,不过group_concat函数比较强大,可以定义分隔符和排序,当然所谓强大是相对的,这里假使我们不知道oracle中的over函数,也不知道listagg函数。

我们先来看看wm_concat函数能实现什么功能,通俗点==>列传行,如果不明白,请看下面截图(可以看到分隔符默认为','顺序也是杂乱的)

        

所以,接下来,我们开始重写wm_concat函数(需要注意和需要说明的地方放在代码注释中...)

(1) 因为需要进行排序,首先自定义一个可变数组

-- 定义可变数组,字符串类型,长度32767,存放列值
CREATE OR REPLACE TYPE WYARRAY as TABLE OF VARCHAR(32767) ;

(2)自定义排序函数、分隔符函数

-- 定义分隔符函数
create or replace function delimiter(colValue in varchar2,
delimiter in varchar2) return varchar2 is
rtnValue varchar2(32767); begin rtnValue := colValue || ' delimiter=>' || delimiter || '; '; return rtnValue; end delimiter;

  

-- 定义排序函数
create or replace function orderby(colValue in varchar2,
orderby in varchar2) return varchar2 is
rtnValue varchar2(32767); begin rtnValue := colValue || ' orderby=>' || LOWER(orderby) || '; '; return rtnValue; end orderby;

 

(3) 重定义oracle接口函数、以及接口函数的实现体(实现分隔符和排序的主要代码)

-- 使用当前用户权限(使用authid current_user,定义type为用户当前用户的权限,举个例子:比如A用户他可以建立表,但是A用户在存储过程中如果建立表可能会提示权限不够,所以需要用authid current_user进行约束)
create or replace type wy_wm_concat authid current_user as object
( --拼接字符串,存放中间值,当然也可以定义为clob,clob会使用临时段,导致临时表空间迅速增大;
--查看wmsys下的function可以发现Oracle10g到oracle11g自带的wm_concat函数的返回类型从clob变成varchar2
currStr VARCHAR2(32767), --分割字符串
delimiter VARCHAR2(64), --排序字符串(asc、desc)
orderby VARCHAR2(64), -- 定义字符串数组
strArray WYARRAY, -- 初始化接口函数
STATIC FUNCTION ODCIAGGREGATEINITIALIZE(init IN OUT wy_wm_concat)
RETURN NUMBER, -- 迭代接口函数
MEMBER FUNCTION ODCIAGGREGATEITERATE(self IN OUT wy_wm_concat,
colValue IN VARCHAR2) RETURN NUMBER, -- 并行时字符串合并的接口函数
MEMBER FUNCTION ODCIAGGREGATEMERGE(self IN OUT wy_wm_concat,
next wy_wm_concat) RETURN NUMBER, -- oracle终止接口函数
MEMBER FUNCTION ODCIAGGREGATETERMINATE(self IN wy_wm_concat,
returnValue OUT VARCHAR2,
flags IN NUMBER)
RETURN NUMBER
)
create or replace type body wy_wm_concat is  --定义函数的body

  --初始化函数
STATIC FUNCTION ODCIAGGREGATEINITIALIZE(init IN OUT wy_wm_concat)
RETURN NUMBER is
begin
init := wy_wm_concat('', ',', 'asc', WYARRAY());
return ODCICONST.Success;
END; -- 字符串拼接,self 为当前聚集函数的指针,用来与前面的计算结果进行关联
MEMBER FUNCTION ODCIAGGREGATEITERATE(self IN OUT wy_wm_concat,
colValue IN VARCHAR2) RETURN NUMBER is tempStr varchar(500); extendStr varchar(500); deStr varchar(100); deLen int default 0; segStr varchar(500); --定义一个二维数组
TYPE varArry IS VARRAY(2) OF VARCHAR2(200); tempArry varArry := varArry('', ''); begin if instr(colValue, ' ', 1) > 0 then
tempStr := substr(colValue, 1, instr(colValue, ' ', 1) - 1);
else
tempStr := colValue;
end if; --排序和分隔符
extendStr := REPLACE(colValue, tempStr || ' '); if instr(extendStr, ' ', 1) > 0 then tempArry(1) := substr(extendStr, 1, instr(extendStr, ' ', 1) - 1); tempArry(2) := substr(extendStr, instr(extendStr, ' ', 1)); for i in 1 .. tempArry.count loop
-- 获取分隔符
if (tempArry(i) is not null) and
(instr(tempArry(i), 'delimiter=>') > 0) THEN deStr := 'delimiter=>'; deLen := length(deStr); segStr := substr(trim(tempArry(i)),
instr(trim(tempArry(i)), deStr) + deLen); self.delimiter := SUBSTR(segStr, 1, instr(segStr, ';', -1) - 1);
END IF; -- 获取排序字符串
if tempArry(i) is not null and
(instr(tempArry(i), 'orderby=>') > 0) THEN deStr := 'orderby=>'; deLen := length(deStr); segStr := substr(trim(tempArry(i)),
instr(trim(tempArry(i)), deStr) + deLen); self.orderby := SUBSTR(segStr, 1, instr(segStr, ';', -1) - 1); END IF; end loop; end if; -- 存放入数组
self.strArray.extend; self.strArray(self.strArray.count) := tempStr; return ODCICONST.Success;
END; --并行操作是用来合并两个聚集函数的两个不同的指针对应的结果
MEMBER FUNCTION ODCIAGGREGATEMERGE(self IN OUT wy_wm_concat,
next wy_wm_concat) RETURN NUMBER is
begin -- 将next数组中元素全部放入self指针对应的数组中
for i in 1 .. next.strArray.count loop self.strArray.extend; self.strArray(self.strArray.count) := next.strArray(i); end loop; return ODCICONST.Success;
END; -- 终止函数,返回结果
MEMBER FUNCTION ODCIAGGREGATETERMINATE(self IN wy_wm_concat,
returnValue OUT VARCHAR2,
flags IN NUMBER) RETURN NUMBER IS
temp_rtnValue varchar2(32767); BEGIN
-- 排序
if INSTR(self.orderby, 'desc') > 0 THEN for x in (select column_value
from Table(self.strArray)
order by 1 DESC) loop temp_rtnValue := temp_rtnValue || self.delimiter || x.column_value; end loop;
ELSE
for x in (select column_value from Table(self.strArray) order by 1 ASC) loop temp_rtnValue := temp_rtnValue || self.delimiter || x.column_value; end loop; END IF; returnValue := ltrim(temp_rtnValue, self.delimiter); return ODCICONST.Success;
END; END;

 

(4)自定义聚集函数

-- 定义聚集函数(未开启并行计算功能)
create or replace function wy_concat(colValue VARCHAR2) RETURN VARCHAR2
AGGREGATE USING wy_wm_concat;

  

至此,主要的代码已经全部奉上,看看运行效果,如下截图:

①看看调用的默认情况(分隔符默认是逗号,排序默认是升序,在初始化函数中如此定义的)

②自定义分隔符(利用分隔符函数将分隔符定义为*)

③降序排序

④去重,为了可以使用wm_concat自带的去重函数,所以在自定义分隔符和排序函数时,实质是实用了字符串处理(如果你觉得处理字符串麻烦,可以自定义 type... as object ,在使用的时候可以很方便,不会用的童鞋可以私下问)

重写Oracle的wm_concat函数,自定义分隔符、排序的更多相关文章

  1. Oracle中wm_concat()函数的使用

    Oracle中wm_concat()函数的使用 wm_concat()函数是oracle行列转换函数,该函数可以把列值以‘,’分割开来,并显示成一行. 1.原数据: 2.把结果分组以‘|’分隔,以一行 ...

  2. Oracle创建WM_CONCAT函数

    Oracle创建WM_CONCAT函数 WM_CONCAT这个函数会出错,所以从 11g开始.官方不认可 WM_CONCAT.然后就没这个函数了, 下面就是创建WM_CONCAT这个函数的步骤 第一步 ...

  3. Oracle的wm_concat函数(转)

    wm_concat函数简单说就是行转列显示. 转自:http://christy-fang.iteye.com/blog/1299850 首先让我们来看看这个神奇的函数wm_concat(列名),该函 ...

  4. oracle的wm_concat函数实现行转列

    有以下数据 deptname phone username isboss 部门A 电话1 员工A 0 部门A 电话1 领导A 1 部门B 电话2 员工B 0 部门B 电话2 员工C 0 部门B 电话2 ...

  5. Oracle没有WM_CONCAT函数的解决办法

    WM_CONCAT是oracle的非公开函数,并不鼓励使用,新版本oracle并没有带此函数,需要手工加上. 1.下载三个文件:owmctab.plb  . owmaggrs.plb . owmagg ...

  6. oracle 的wm_concat函数使用

    转载自:http://blog.itpub.net/post/42245/522757 首先让我们来看看这个神奇的函数wm_concat(列名),该函数可以把列值以","号分隔起来 ...

  7. oracle 行列转换函数之WM_CONCAT和LISTAGG的使用(一)

    一.wm_concat函数 wm_concat能够实现同样的功能,但是有时在11g中使用需要用to_char()进行转换,否则会出现不兼容现象(WMSYS.WM_CONCAT: 依赖WMSYS 用户, ...

  8. ORACLE自定义顺序排序-转

    ORACLE可以借助DECODE函数,自定义顺序排序: select * from ( select 'Nick' as item from dual union all select 'Viki' ...

  9. oracle wm_concat 函数无法使用的情况下,使用LISTAGG()函数

    http://dacoolbaby.iteye.com/blog/1698957 --20180327 重写wm_concat函数,解决行数超过上限问题 /*执行前请将APPS替换为当前登录用户*/ ...

随机推荐

  1. Ant_build.xml的最完整解释

    Ant的概念Make命令是一个项目管理工具,而Ant所实现功能与此类似.像make,gnumake和nmake这些编译工具都有一定的缺陷,但是Ant却克服了这些工具的缺陷.最初Ant开发者在开发跨平台 ...

  2. entityframework学习笔记--001

    最近想重新好好学习一下entityframework,于是在院子里找到了一篇不错的博客.下面把学习的过程记录下来,方便以后复习. 学习过程参考大神的博客:http://www.cnblogs.com/ ...

  3. 弄一个ajax笔记方便查询-基础知识篇

    jQuery对Ajax做了大量的封装,jQuery采用了三层封装: 最底层的封装方法为:$.ajax() 通过最底层进一步封装了第二层的三种方法:.load().$.get().$.post() 最高 ...

  4. 【blade的UI设计】理解前端MVC与分层思想

    前言 最近校招要来了,很多大三的同学一定按捺不住心中的焦躁,其中有期待也有彷徨,或许更多的是些许担忧,最近在开始疯狂的复习了吧 这里小钗有几点建议给各位: ① 不要看得太重,关心则乱,太紧张反而表现不 ...

  5. App Store2016年最新审核规则

    为App Store开发程序,开发者必须遵守 Program License Agreement (PLA).人机交互指南(HIG)以及开发者和苹果签订的任何协议和合同. 以下规则和示例旨在帮助开发者 ...

  6. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  7. 在 CentOS7 上安装 MongoDB

    在 CentOS7 上安装 MongoDB 1 通过 SecureCRT 连接至 CentOS7 服务器: 2 进入到 /usr/local/ 目录: cd /usr/local 3 在当前目录下创建 ...

  8. 编写Javascript类库(jQuery版) - 进阶者系列 - 学习者系列文章

    这些年主要关注于项目管理方面的工作,编码就比较少了.这几天比较空闲,就想把原来的经验沉淀下来,一个是做好记录,以后如果忘记了还能尽快找回来,第二个是写写博文,算是练练手笔吧. 言归正传,这次写的是Ja ...

  9. 版本管理-SVN本地版本管理

    0. 引言 使用工具是人与动物的基本区别,善用工具可以极大的提高效率,降低错误率.在PC软件领域,有很多好用的工具,这些工具都是软件工程重要的基础设施.然而,嵌入式开发,在其代码数量上,很多时候由于没 ...

  10. Bw树:新硬件平台的B树(内存数据库中的b树索引)

    Bw树:新硬件平台的B树 Bw树:新硬件平台的B树 1. 概述 1.1 原子记录存储(Atomic Record Stores) 1.2 新的环境 1.3 实现 2 Bwtree的体系结构 2.1 现 ...