ORACLE学习笔记(六)——自定义聚合函数

一、用户自定义聚合函数简介

 

     Oracle提供了很多预定义好的聚集函数,比如Max(), Sum(), AVG(),但是这些预定义的聚集函数基本上都是适应于标量数据(scalar data),对于复杂的数据类型,比如说用户自定义的Object type, Clob等,是不支持的。

     但是,幸运的是,用户可以通过实现Oracle的ExtensibilityFramework中的ODCIAggregateinterface来创建自定义聚集函数,而且自定义的聚集函数跟内建的聚集函数用法上没有差别。ODCI是Oracle DataCartridge Interface 几个单词的首字母缩写。

二、Overview of User-Defined Aggregate Functions——用户自定义聚合函数概述

      通过实现ODCIAggregaterountines来创建自定义的聚集函数。可以通过定义一个对象类型(Object Type),然后在这个类型内部实现ODCIAggregate 接口函数(routines),可以用任何一种Oracle支持的语言来实现这些接口函数,比如C/C++, JAVA, PL/SQL等。在这个Object Type定义之后,相应的接口函数也都在该Object Type Body内部实现之后,就可以通过CREATE FUNCTION语句来创建自定义的聚集函数了。

      每个自定义的聚集函数需要实现4个ODCIAggregate 接口函数,这些函数定义了任何一个聚集函数内部需要实现的操作,这些函数分别是 initialization, iteration, merging 和termination。

      (1)ODCIAggregateInitialize这个函数用来执行初始化操作(initialization). Oracle会调用这个函数来初始化自定义函数计算。初始化的聚集环境(aggregationcontext)会以对象实例(objecttype instance)传回给oracle.

      (2)ODCIAggregateIterate这个函数用来遍历需要处理的数据,被oracle重复调用。每次调用的时候,当前的aggreation context 和新的(一组)值会作为传入参数。这个函数会处理这些传入值,然后返回更新后的aggregation context. 这个函数对每一个NON-NULL的值都会被执行一次。NULL值不会被传递个聚集函数。

       (3)ODCIAggregateMerge 这个函数用来把两个aggregationcontext整合在一起,一般用来并行计算中(当一个函数被设置成enable parallel 处理的时候)。

       (4)ODCIAggregateTerminate 这个函数是Oracle调用的最后一个函数。它接收aggregationcontext作为参数,返回最后的aggregate value.

--Example: 下面介绍自定义聚集函数是如何工作的
SELECT AVG(T.Sales)FROM AnnualSales TGROUPBY T.State;
--为了完成求平均值的计算,AVG函数经历下面几个步骤:
--(1) Initializes: 初始化AggregationContext:
runningSum = 0;  runningCount = 0;
--(2) Iteratively 处理每个连续的输入,同时更新aggregation context:
runningSum += inputval; runningCount ++;
--(3) 【这步可选】Merge 整合两个aggregationcontext 返回一个aggregation context. 如果需要这一步的话,它是在termination之前执行。
runningSum = runningSum1 + runningSum2;
runningCount = runningCount1 + runningCount2;
--(4) Terminates 计算出最后的结果,通过最后的aggregation context来返回最后的aggregated value.
return (runningSum / runningCount);
--如果AVG是自定义的聚集函数的话,与之相对应的对象类型(object type)需要实现对应的ODCIAggregate的接口函数。
--变量runningSum 和 runningCount 是对象类型中的属性(attribute). 

三、Creating a User-Defined Aggregate——创建用户自定义聚合函数

        创建一个自定义聚集函数分成两步:如下面两个例子所示:

--Example: 如何实现ODCIAggregate接口:
CREATE TYPE SpatialUnionRoutines(
	STATIC FUNCTION ODCIAggregateInitialize( ... ) ...,
	MEMBER FUNCTION ODCIAggregateIterate(...) ... ,
	MEMBER FUNCTION ODCIAggregateMerge(...) ..., 
	MEMBER FUNCTION ODCIAggregateTerminate(...)
	); 
CREATE TYPE BODY SpatialUnionRoutines IS ...END;  
--Example:如何定义自定义聚集函数:
CREATE FUNCTION SpatialUnion(x Geometry)
    RETURN Geometry AGGREGATE USING SpatialUnionRoutines; 

        注意在定义函数的时候需要通过Aggregate Using语句来关联对应的实现了ODCIAggregate接口的Object Type。

四、Using a User-Defined Aggregate——使用用户自定义聚合函数

        自定义的聚集函数可以像内置的聚集函数一样使用,可以用在SELECT, ORDER BY, HAVING语句中。下面几个例子说明如何使用上面定义的自定义函数SpatialUnion

--Example: 用在Select语句中
SELECT SpatialUnion(geometry) FROM counties GROUP BY state;
--Example: 用在Having语句中,
SELECT groupcol, MyUDAG(col) FROM tabGROUPBY groupcol HAVING MyUDAG(col) > 100ORDER BY MyUDAG(col); 
--Example: 其他
SELECT ..., MyUDAG(col) FROM tabGROUP BY ROLLUP(gcol1, gcol2); 

          自定义聚集函数可以跟All, Distinct一起使用,亦可以用在Group by的扩展语句中,像ROLLUP, CUBE, grouping sets.

五、Evaluating User-Defined Aggregates in Parallel——并行评估用户自定义聚集函数

          跟内置的聚集函数一样,自定义的聚集函数也可以并行来处理,需要注意的是,自定义的聚集函数需要声明为parallel-enabled, 如下:

CREATE FUNCTION MyUDAG(...)
    RETURN...PARALLEL_ENABLE AGGREGATE USING MyAggrRoutines; 

六、User-Defined Aggregates and Analytic Functions——用户自定义聚合和分析函数

          自定义的聚集函数可以被当做Analytic函数来用:

SELECT Account_number,Trans_date,Trans_amount,MyAVG(Trans_amount)OVER PARTITION BY Account_number 
    ORDER BY Trans_date RANGE INTERVAL'7' DAY PRECEDING AS mavg_7day FROM Ledger;

七、Reusing the Aggregation Context for Analytic Function——分析函数复用聚合文本

          当一个自定义的聚集函数被用来做Analytic Function的时候,对每条记录对应的window都会计算一次aggregate。一般的说来,每个连续的窗口包含大部分相同的数据集合。

          可以通过实现ODCIAggregateDelete接口函数来让Oracle更有效地复用aggregation context.

八、An complete example forCreating and Using a User-Defined Aggregate Function——创建和使用用户自定义聚合函数的完整示例

         SecondMax()返回一组数里面第二大的那个值。

           ①、实现类型SecondMaxImpl,该类型包含了ODCIAggregate接口函数,

create type SecondMaxImpl as object(
        --保存最大值,这部分内容根据聚合函数操作的不同,有用户自行设置
        max NUMBER,
        --保存第二大的值,这部分内容根据聚合函数操作的不同,有用户自行设置        
        secmax NUMBER,
        --(该步骤是必须的)初始化函数,必须要实现的方法,用于在聚合运算的最开始部分,初始化上下文环境  
        static function ODCIAggregateInitialize(sctxIN OUT SecondMaxImpl) return number, 
        --(该步骤是必须的)迭代运算函数,oracle依据该函数进行迭代运算,第一个参数为聚合运算的上下文,  
        --第二个参数为当前需要处理的值,可以为number varchar2等类型,  
        --在迭代过程中,如果当前值为null,则忽略该次迭代  
	member function ODCIAggregateIterate(self IN OUT SecondMaxImpl,value IN number) return number, 
        --(该步骤是必须的,但在执行中,oracle会有选择执行该步骤)该函数用于合并两个上下文到一个上下文中,在并行和串行环境下均有可能发挥作用 
	member function ODCIAggregateTerminate(selfIN SecondMaxImpl,returnValue OUT number, flags IN number) return number,
        --(该步骤是必须的)该函数在聚合运算的最后一步运行,用于对结果进行处理并返回处理结果,  
        --第一个参数为上下文,第二个参数为返回值,可以为number,varchar2等类型  
        --第三个参数为标识位  
        member function ODCIAggregateMerge(self IN OUT SecondMaxImpl,ctx2 IN SecondMaxImpl) return number
	);

           ②实现类型SecondMaxImpl的body

create or replace type body SecondMaxImplis

    static function ODCIAggregateInitialize(sctx IN OUT SecondMaxImpl) return number IS 
        begin  
	    sctx := SecondMaxImpl(0,0);  
	    return ODCIConst.Success;
	end; 
		 
     member function ODCIAggregateIterate(self IN OUT SecondMaxImpl, value IN number)return number IS 
         begin  
             if value >self.max then    
	         self.secmax :=self.max;    
	         self.max := value;  
	     else if value > self.secmax then    
	         self.secmax := value;  
	     end if; 
		 return ODCIConst.Success;
          end; 
		
     member function ODCIAggregateTerminate(self IN SecondMaxImpl,return Value OUT number, flags IN number) return number IS 
         begin 
             return Value := self.secmax; 
	     return ODCIConst.Success;
	 end; 
		
      member function ODCIAggregateMerge(self IN OUT SecondMaxImpl, ctx2 IN SecondMaxImpl) return number IS 
          begin  
	        if ctx2.max > self.max then    
	            if ctx2.secmax > self.secmax then       
		        self.secmax := ctx2.secmax;    
		    else 
		        self.secmax := self.max;    
		    end if;    
		    self.max := ctx2.max;  
		else if ctx2.max > self.secmax then    
		    self.secmax := ctx2.max;  
		end if; 
		return ODCIConst.Success;
	   end;
end; 

           ③创建自定义聚集函数SecondMax()

CREATE FUNCTION SecondMax (input NUMBER) RETURN NUMBER PARALLEL_ENABLE AGGREGATE USING SecondMaxImpl; 

           ④使用自定义聚集函数SecondMax()

SELECT SecondMax(salary),department_id FROM employees GROUP BY department_id HAVING SecondMax(salary) > 9000;

 

 

注:该资料主要来源于某位大神对ORACLE文档的翻译

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值