While explaining some concepts over CTE, was asked with a cute question.. can we find the multiplication of rows , while we always concentrate on the SUM()
from a fresher. That gave me a thought! Is it ever possible with just an SQL. I was also considering the maximum number precision we can even support, since the product may be so huge.
Having said, we cant write our own aggregate function.(can we?) I am thinking is it ever possible with SQL only.
I thought of 2*3
is like adding 2 , 3 times to itself.. but when the set is huge.. I cant make it possible as it may be cumbersome.
Aonther possibility is log (a+b) = log a * log b;
and Anti logarithm
, gives you the result. This is what i managed to respond. For Oracle, I would have a function using EXECUTE IMMEDIATE
.
Can we actually multiply itself. Which will be more beautiful SQL-ly.. This is for pure learning experience.
Advertisement
Answer
Oracle has exposed these ODCI (Oracle Data Cartridge Interface) methods to do the Aggregate! Reference:
- ODCIAggregateDelete() – Removes an input value from the current group.
- ODCIAggregateInitialize() – Initializes the aggregation context and instance of the implementation object type, and returns it as an OUT parameter.
- ODCIAggregateIterate() – Iterates through input rows by processing the input values, updating and then returning the aggregation context.
- ODCIAggregateMerge() – Merges two aggregation contexts into a single object instance during either serial or parallel evaluation of the user-defined aggregate.
- ODCIAggregateTerminate() – Calculates the result of the aggregate computation and performs all necessary cleanup, such as freeing memory.
- ODCIAggregateWrapContext() Integrates all external pieces of the current aggregation context to make the context self-contained.
Code For PRODUCT() Aggregate function :
CREATE OR REPLACE type PRODUCT_IMPL AS object ( result NUMBER, static FUNCTION ODCIAggregateInitialize(sctx IN OUT PRODUCT_IMPL) RETURN NUMBER, member FUNCTION ODCIAggregateIterate(self IN OUT PRODUCT_IMPL, value IN NUMBER) RETURN NUMBER, member FUNCTION ODCIAggregateTerminate( self IN PRODUCT_IMPL, returnValue OUT NUMBER, flags IN NUMBER) RETURN NUMBER, member FUNCTION ODCIAggregateMerge(self IN OUT PRODUCT_IMPL, ctx2 IN PRODUCT_IMPL ) RETURN NUMBER ); / /* 1.Initializes the computation by initializing the aggregation context—the rows over which aggregation is performed: */ CREATE OR REPLACE type body PRODUCT_IMPL IS static FUNCTION ODCIAggregateInitialize(sctx IN OUT PRODUCT_IMPL) RETURN NUMBER IS BEGIN sctx := PRODUCT_IMPL(1); RETURN ODCIConst.Success; END; /* 2.Iteratively processes each successive input value and updates the context: */ member FUNCTION ODCIAggregateIterate(self IN OUT PRODUCT_IMPL, value IN NUMBER) RETURN NUMBER IS BEGIN self.result := value * self.result; RETURN ODCIConst.Success; END; member FUNCTION ODCIAggregateTerminate( self IN PRODUCT_IMPL, returnValue OUT NUMBER, flags IN NUMBER) RETURN NUMBER IS BEGIN returnValue := self.result; RETURN ODCIConst.Success; END; member FUNCTION ODCIAggregateMerge(self IN OUT PRODUCT_IMPL, ctx2 IN PRODUCT_IMPL) RETURN NUMBER IS BEGIN self.result := self.result; RETURN ODCIConst.Success; END; END; / /* Create A function using the PRODUCT_IMPL implementation we did above */ CREATE OR REPLACE FUNCTION product(input NUMBER) RETURN NUMBER PARALLEL_ENABLE AGGREGATE USING PRODUCT_IMPL; /
Results:
SELECT group_name,product(num) FROM product_test GROUP BY group_name; Mahesh -60000 Mahesh_1 9