热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:重写Oracle的wm_concat函数,自定义分隔符排序

篇首语:本文由编程笔记#小编为大家整理,主要介绍了重写Oracle的wm_concat函数,自定义分隔符排序相关的知识,希望对你有一定的参考价值。&

篇首语:本文由编程笔记#小编为大家整理,主要介绍了重写Oracle的wm_concat函数,自定义分隔符排序相关的知识,希望对你有一定的参考价值。



        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 ,在使用的时候可以很方便,不会用的童鞋可以私下问)

   

   



推荐阅读
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
author-avatar
低调的小男2502928607
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有