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