重写oracle wm_contact函数脚本

最近项目上有个要求,要把连续的卡号使用一个段来描述,比如:1,2,3,4,5,8,10,13,14,15,16 要显示成:1-5,8,10,13-16的形式

但是原有的wm_contact函数是用逗号隔开,并没有该功能,我在网上搜集了点资料,自己再修改了点东西,满足了这个需求,下面看代码:

此代码是重写 wm_contact 函数的主要代码,脚本中 FUN_JOIN_STR(CURR_STR,‘-‘)  函数是我自定义的函数

create or replace TYPE zh_concat_im
AUTHID CURRENT_USER AS OBJECT
(
  CURR_STR clob,
  STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT zh_concat_im) RETURN NUMBER,
  MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT zh_concat_im,
  P1 IN VARCHAR2) RETURN NUMBER,
  MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN zh_concat_im,
  RETURNVALUE OUT VARCHAR2,
  FLAGS IN NUMBER)
  RETURN NUMBER,
  MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT zh_concat_im,
  SCTX2 IN zh_concat_im) RETURN NUMBER
);
/
create or replace TYPE BODY zh_concat_im
IS
  STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT zh_concat_im)
  RETURN NUMBER
  IS
  BEGIN
  SCTX := zh_concat_im(NULL) ;
  RETURN ODCICONST.SUCCESS;
  END;
  MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT zh_concat_im,
  P1 IN VARCHAR2)
  RETURN NUMBER
  IS
  BEGIN
  --DBMS_OUTPUT.PUT_LINE(CURR_STR||'|'||P1);
  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 zh_concat_im,
  RETURNVALUE OUT VARCHAR2,
  FLAGS IN NUMBER)
  RETURN NUMBER
  IS
  BEGIN
  RETURNVALUE :=<span style="color:#ff6666;">FUN_JOIN_STR(CURR_STR,'-');  --此处要在该函数返回之前再进行一次处理</span>
  RETURN ODCICONST.SUCCESS;
  END;
  MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT zh_concat_im,
  SCTX2 IN zh_concat_im)
  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 zh_concat(P1 VARCHAR2)
RETURN VARCHAR2 AGGREGATE USING zh_concat_im;
/

以下是自定义函数部分,主要完成排序和拼接

CREATE OR REPLACE TYPE T_RET_TABLE IS TABLE OF VARCHAR2(30);--定义类型
/
CREATE OR REPLACE FUNCTION FUN_STRSPLIT_TABLE(V_STR     IN CLOB,
                                              VAR_SPLIT IN VARCHAR2)
  RETURN T_RET_TABLE
  PIPELINED IS
  VAR_TMP     CLOB;
  VAR_ELEMENT VARCHAR2(30);
  N_LENGTH    NUMBER := LENGTH(VAR_SPLIT);
BEGIN
  VAR_TMP := V_STR||',';
  WHILE INSTR(VAR_TMP, VAR_SPLIT) > 0 LOOP
    VAR_ELEMENT := SUBSTR(VAR_TMP, 1, INSTR(VAR_TMP, VAR_SPLIT) - 1);
    VAR_TMP     := SUBSTR(VAR_TMP,
                          INSTR(VAR_TMP, VAR_SPLIT) + N_LENGTH,
                          LENGTH(VAR_TMP));
    PIPE ROW(VAR_ELEMENT);
  END LOOP;
  RETURN;
END FUN_STRSPLIT_TABLE;
/
CREATE OR REPLACE FUNCTION FUN_JOIN_STR(V_SOURCE_STR IN CLOB,
                                        V_JOIN_STR   IN VARCHAR2)
  RETURN CLOB IS
  V_RESULT   CLOB;
  V_STR_ARRY T_RET_TABLE;
  V_MINUS    INTEGER;
  V_COUNT    INTEGER := 0;
  V_RANGE_STR VARCHAR2(50);
BEGIN
  SELECT COLUMN_VALUE BULK COLLECT
    INTO V_STR_ARRY
    FROM TABLE(FUN_STRSPLIT_TABLE(V_SOURCE_STR, ','))
   ORDER BY COLUMN_VALUE;
  FOR N IN 1 .. V_STR_ARRY.COUNT LOOP
    IF N = 1 THEN
      V_RESULT := V_STR_ARRY(N);
      V_RANGE_STR :=V_RESULT;
    END IF;
    IF N > 1 THEN
      V_MINUS := TO_NUMBER(V_STR_ARRY(N)) - TO_NUMBER(V_STR_ARRY(N - 1));
      IF V_MINUS > 1 THEN
        IF V_COUNT > 1 THEN
          V_RESULT := V_RESULT||','||V_RANGE_STR||V_JOIN_STR||V_STR_ARRY(N-1);
          V_COUNT := 0;
        ELSE
          V_RESULT := V_RESULT|| ','|| V_STR_ARRY(N);
        END IF;
        V_RANGE_STR :=V_STR_ARRY(N);
      ELSE
        V_COUNT := V_COUNT + 1;
      END IF;
    END IF;
  END LOOP;
  IF V_COUNT>0 THEN
     V_RESULT := V_RESULT||','||V_RANGE_STR||V_JOIN_STR||V_STR_ARRY(V_STR_ARRY.COUNT);
  END IF;
  RETURN(V_RESULT);
END FUN_JOIN_STR;
/

调用示例:

SELECT zh_concat(A.CARDNO) FROM CM_CARDDATA A WHERE A.SESSIONNUMBER=117 GROUP BY A.CM_BASE_CARDTYPEOID;

使用wm_contact 输出的数据如下:

9007001,9900011,9700009,9700001,9700011,9700002,9700008,9700003,9700012,9990007,9990006,9990005,9990004,9990003,9990002,9990001,9650201,9700013,9911021,9700006,9780040,9780044,9911021,9464603,9464601,9214509,9214510,9780046,9780057,9780056,9780055,9900082,9780054,9780045,9780043,9780042,9700007,9780041,9780053,9780052,9780051,9990014,9990013,9990012,9990011,9650126,9700005,9700004,9990010,9990009,9990008

使用zh_contact 函数输出的数据如下:

9007001,9214509,9464601,9464603,9650126,9650201,9700001,9700001-9700009,9700011-9700013,9780040-9780046,9780051-9780057,9900082,9911021,9990001,9990001-9990014

代码连接下载地址:点击打开链接

欢迎各位大师前来点评,并优化

时间: 2024-10-10 17:25:00

重写oracle wm_contact函数脚本的相关文章

重写Oracle的wm_concat函数,自定义分隔符、排序

oracle中,wm_concat函数是一个聚合函数,和mysql中的group_concat函数类似,不过group_concat函数比较强大,可以定义分隔符和排序,当然所谓强大是相对的,这里假使我们不知道oracle中的over函数,也不知道listagg函数. 我们先来看看wm_concat函数能实现什么功能,通俗点==>列传行,如果不明白,请看下面截图(可以看到分隔符默认为','顺序也是杂乱的)          所以,接下来,我们开始重写wm_concat函数(需要注意和需要说明的地方

Oracle之函数学习以及事务

Oracle之函数学习 1.字符函数是oracle中最常用的函数 lower(char):将字符串转化为小写的格式 upper(char):将字符串转化为大写的格式 length(char):返回字符串的长度 substr(char,m,n):取字符串的子串 将所有的员工的名字按小写的方式显示? SQL> select lower(ename),sal from emp; LOWER(ENAM        SAL ---------- ---------- smith            

Oracle排名函数(Rank)实例详解

这篇文章主要介绍了Oracle排名函数(Rank)实例详解,需要的朋友可以参考下 --已知:两种排名方式(分区和不分区):使用和不使用partition --两种计算方式(连续,不连续),对应函数:dense_rank,rank ·查询原始数据:学号,姓名,科目名,成绩 select * from t_score S_ID S_NAME SUB_NAME SCORE 1 张三 语文 80.00 2 李四 数学 80.00 1 张三 数学 0.00 2 李四 语文 50.00 3 张三丰 语文 1

[主机/oracle/msyql] 监控脚本

为了方便自己测试和监控,写了三个监控的脚本. 分别监控: 主机[cpu,mem,disk,fs,net] oracle mysql 脚本如下: hmon.py: monitor Linux os system including cpu,memory,disk,net,file system at a regular interval. mmon.py: monitor MySQL DataBase with innodb engine on Linux platform at a regula

数据库编程1 Oracle 过滤 函数 分组 外连接 自连接

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> 数据库编程1 Oracle 过滤 函数 分组 外连接 自连接 本文实验基于的数据表: winsows安装好Oracle11g之后,开始实验 SQLplus 登陆 ORacle sqlplus 退出的方式 查看用户之下有什么表 查看表的所有记录,不区分大小写 设置SQLplus行宽,页宽,列宽: 清屏命令 select as 语法 1,as别名的使用 2,没有引号带有空格的别名,无法识别: 3,带有

数据库编程2 Oracle 过滤 函数 分组 外连接 自连接

[本文谢绝转载原文来自http://990487026.blog.51cto.com] 续:数据库编程1 Oracle 过滤 函数 分组 外连接 自连接 where like模糊查询,查询员工姓名是4个字母 SQL> select * from emp where ename like '____';      EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM    

Oracle trunc()函数的用法

--Oracle trunc()函数的用法 /**************日期  TRUNC()函数没有秒的精确 ********************/ select sysdate from dual --当时日期 select trunc(sysdate) from dual select trunc(sysdate ,'DD') from dual --今天日期 select trunc(sysdate,'d')+7 from dual --本周星期日 select trunc(sys

Oracle常用函数

前一段时间学习Oracle 时做的学习笔记,整理了一下,下面是分享的Oracle常用函数的部分笔记,以后还会分享其他部分的笔记,请大家批评指正. 1.Oracle 数据库中的to_date()函数的使用: 往emp表中插入一条记录: SQL> insert into emp values(1234,'LIZELU','BOSS',1234,'1980-12-06',10000.0,0,30); insert into emp values(1234,'LIZELU','BOSS',1234,'1

oracle 时间函数

加法 select sysdate,add_months(sysdate,12) from dual; --加1年 select sysdate,add_months(sysdate,1) from dual; --加1月 select sysdate,to_char(sysdate+7,'yyyy-mm-dd HH24:MI:SS') from dual; --加1星期 select sysdate,to_char(sysdate+1,'yyyy-mm-dd HH24:MI:SS') from