Row Data Multiplication in Oracle
Aggregate functions return a single result row based
 on a group of rows. This differentiates them from Single-Row functions 
which act on each row. These functions are extensively used with the 
GROUP BY clause in SQL statements. AVG (), COUNT (), SUM () … are few 
aggregate functions which are quite commonly used. Today, one of my 
colleague asked me if there is some aggregation function for Multiplication. I thought about it for a while and found myself surprised that I have never thought about doing such a thing :)
So,
 How do we do the multiplication then? I tried it but just couldn’t do 
it in SQL. So, I asked this question on our internal self help channel 
and I got a pretty impressive reply:
“Using a mathematical approach…”After understanding the solution, I was surprisingly happy with the simplicity of the approach and found it worth sharing. Let’s assume that we have a table “tbl” with one column “num”. This table has three rows having values 2, 3 & 4 for column “num”.
| WITHtbl AS     (SELECT2 num        FROMDUAL      UNION      SELECT3 num        FROMDUAL      UNION      SELECT4 num        FROMDUAL)SELECTnum  FROMtbl;  | 
There is no such function as MUL () in Oracle (I actually tried using it). Here comes the computational part of the puzzle. A multiplication operation can be mathematically expressed as:
MUL (num) = EXP (SUM (LN (num)))
Not very clear at first, I agree. Lets review the maths behind it:
x = (2 * 3 * 4)
ln(x) = ln(2 * 3 * 4)
ln(x) = ln(2) + ln(3) + ln(4) => SUM(LN(num))
ln(x) = .693 + 1.098 + 1.386
ln(x) = 3.178
x = e (3.178) => EXP(SUM(LN(num)))
x = 24
And that’s it. We just created our own multiplication function and now the result can be calculated as:
|   WITHtbl AS     (SELECT2 num        FROMDUAL      UNION      SELECT3 num        FROMDUAL      UNION      SELECT4 num        FROMDUAL)SELECTEXP (SUM(LN (num))) MUL  FROMtbl;  | 
Everything looks perfect. But hey, I have got negative values. The moment you put a negative value in the dataset, you are bound to get the following Oracle error:
“ORA-01428: argument ‘x’ is out of range”
This is because the range for LN () argument is > 0. But this is now easy to handle, here is how:
| WITHtbl AS     (SELECT-2 num        FROMDUAL      UNION      SELECT-3 num        FROMDUAL      UNION      SELECT-4 num        FROMDUAL),     sign_val AS     (SELECTCASEMOD (COUNT(*), 2)                WHEN0 THEN1                ELSE-1             ENDval        FROMtbl       WHEREnum < 0)SELECTEXP (SUM(LN (ABS(num)))) * val    FROMtbl, sign_valGROUPBYval  | 
So, we first counted the negative records in the table. If the count is odd, the final result should be negative and vice versa. We then multiplied this signed value with the multiplication of the absolute values. A subquery can also be used instead of GROUP BY but that’s trivial. Now the solution is complete and we are able to handle the negative values too.

Comments
Post a Comment