您的位置:首页 > 数据库 > Oracle

[Oracle Data Cartridge Interface] User-Defined Aggregation Functions

2009-12-28 14:29 381 查看
本文基本上是对Orace文档(http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14289/dciaggfns.htm#sthref542)的翻译。

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

但是,幸运的是,用户可以通过实现Oracle的ExtensibilityFramework中的ODCIAggregateinterface来创建自定义聚集函数,而且自定义的聚集函数跟内建的聚集函数用法上没有差别。

ODCI是OracleDataCartridgeInterface几个单词的首字母缩写,关于OracleDataCartridge,可以参见这里。

1.OverviewofUser-DefinedAggregateFunctions

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

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

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

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

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

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

Example:自定义聚集函数是如何工作的

SELECTAVG(T.Sales)
FROMAnnualSalesT
GROUPBYT.State;


为了完成求平均值的计算,AVG函数经历下面几个步骤:

(1)Initializes:初始化AggregationContext:

runningSum=0;runningCount=0;

(2)Iteratively处理每个连续的输入,同时更新aggregationcontext:

runningSum+=inputval;runningCount++;

(3)【这步是可选的】Merge整合两个aggregationcontext返回一个aggregationcontext.如果需要这一步的话,它是在termination之前执行。

runningSum=runningSum1+runningSum2;

runningCount=runningCount1+runningCount2;

(4)Terminates计算出最后的结果,通过最后的aggregationcontext来返回最后的aggregatedvalue.

return(runningSum/runningCount);

如果AVG是自定义的聚集函数的话,与之相对应的对象类型(objecttype)需要实现对应的ODCIAggregate的接口函数。变量runningSum和runningCount是对象类型中的属性(attribute).

2.CreatingaUser-DefinedAggregate

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

Example:如何实现ODCIAggregate接口:

CREATETYPESpatialUnionRoutines(
STATICFUNCTIONODCIAggregateInitialize(...)...,
MEMBERFUNCTIONODCIAggregateIterate(...)...,
MEMBERFUNCTIONODCIAggregateMerge(...)...,
MEMBERFUNCTIONODCIAggregateTerminate(...)
);
CREATETYPEBODYSpatialUnionRoutinesIS
...
END;


Example:如何定义自定义聚集函数:

CREATEFUNCTIONSpatialUnion(xGeometry)RETURNGeometry
AGGREGATEUSINGSpatialUnionRoutines;


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

3.UsingaUser-DefinedAggregate

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

Example:用在Select语句中

SELECTSpatialUnion(geometry)
FROMcounties
GROUPBYstate


Example:用在Having语句中,

SELECTgroupcol,MyUDAG(col)
FROMtab
GROUPBYgroupcol
HAVINGMyUDAG(col)>100
ORDERBYMyUDAG(col);


Example:其他

SELECT...,MyUDAG(col)
FROMtab
GROUPBYROLLUP(gcol1,gcol2)


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

4.EvaluatingUser-DefinedAggregatesinParallel

跟内置的聚集函数一样,自定义的聚集函数也可以并行来处理,如下图



需要注意的是,自定义的聚集函数需要声明为parallel-enabled,如下

CREATEFUNCTIONMyUDAG(...)RETURN...
PARALLEL_ENABLEAGGREGATEUSINGMyAggrRoutines;


5.User-DefinedAggregatesandAnalyticFunctions

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

SELECTAccount_number,Trans_date,Trans_amount,
MyAVG(Trans_amount)OVER
PARTITIONBYAccount_numberORDERBYTrans_date
RANGEINTERVAL'7'DAYPRECEDING)ASmavg_7day
FROMLedger;


6.ReusingtheAggregationContextforAnalyticFunctions

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

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

7.AncompleteexampleforCreatingandUsingaUser-DefinedAggregateFunction

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

(1)实现类型SecondMaxImpl,该类型包含了ODCIAggregate接口函数,

createtypeSecondMaxImplasobject
(
maxNUMBER,--highestvalueseensofar
secmaxNUMBER,--secondhighestvalueseensofar
staticfunctionODCIAggregateInitialize(sctxINOUTSecondMaxImpl)
returnnumber,
memberfunctionODCIAggregateIterate(selfINOUTSecondMaxImpl,
valueINnumber)returnnumber,
memberfunctionODCIAggregateTerminate(selfINSecondMaxImpl,
returnValueOUTnumber,flagsINnumber)returnnumber,
memberfunctionODCIAggregateMerge(selfINOUTSecondMaxImpl,
ctx2INSecondMaxImpl)returnnumber
);
/


(2).实现类型SecondMaxImpl的body,

createorreplacetypebodySecondMaxImplis
staticfunctionODCIAggregateInitialize(sctxINOUTSecondMaxImpl)
returnnumberis
begin
sctx:=SecondMaxImpl(0,0);
returnODCIConst.Success;
end;
memberfunctionODCIAggregateIterate(selfINOUTSecondMaxImpl,valueINnumber)returnnumberis
begin
ifvalue>self.maxthen
self.secmax:=self.max;
self.max:=value;
elsifvalue>self.secmaxthen
self.secmax:=value;
endif;
returnODCIConst.Success;
end;
memberfunctionODCIAggregateTerminate(selfINSecondMaxImpl,
returnValueOUTnumber,flagsINnumber)returnnumberis
begin
returnValue:=self.secmax;
returnODCIConst.Success;
end;
memberfunctionODCIAggregateMerge(selfINOUTSecondMaxImpl,ctx2INSecondMaxImpl)returnnumberis
begin
ifctx2.max>self.maxthen
ifctx2.secmax>self.secmaxthen
self.secmax:=ctx2.secmax;
else
self.secmax:=self.max;
endif;
self.max:=ctx2.max;
elsifctx2.max>self.secmaxthen
self.secmax:=ctx2.max;
endif;
returnODCIConst.Success;
end;
end;
/


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

CREATEFUNCTIONSecondMax(inputNUMBER)RETURNNUMBER
PARALLEL_ENABLEAGGREGATEUSINGSecondMaxImpl;


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

SELECTSecondMax(salary),department_id
FROMemployees
GROUPBYdepartment_id
HAVINGSecondMax(salary)>9000;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: