2012-11-29 48 views
2

我有一個查詢,看起來像這樣:PLSQL累積乘法

SELECT SUM(CAPITAL_RETURN) OVER (PARTITION BY PORTF_CODE, 
           EXTRACT(MONTH FROM END_DATE) ORDER BY END_DATE 
           ) AS CUM_CAPITAL_RET, 
FROM 
.... 

這是罰款創建累積和列,但我現在需要創建一個累積乘法列。

這可能嗎?

感謝

回答

1

做的傳統方式,這是通過取值的對數的總和的指數,同時注意正確處理底片零。

2
  1. 您可以編寫用戶定義的聚合函數。這裏有一個例子:

    SQL> create or replace type t_multiply as object 
        2 (
        3 total number, 
        4 
        5 static function ODCIAggregateInitialize(nctx IN OUT t_multiply) 
        6 return number, 
        7 
        8 member function ODCIAggregateIterate(self IN OUT t_multiply , 
        9           value number) 
    10 return number, 
    11 
    12 member function ODCIAggregateTerminate(self IN t_multiply, 
    13           retVal OUT number, 
    14           flags IN number) 
    15 return number, 
    16 
    17 member function ODCIAggregateMerge(self IN OUT t_multiply, 
    18          ctx2 IN t_multiply) 
    19 return number 
    20 ) 
    21/
    
    Type created 
    
    SQL> create or replace type body t_multiply 
        2 is 
        3 
        4 static function ODCIAggregateInitialize(nctx IN OUT t_multiply) 
        5 return number 
        6 is 
        7 begin 
        8  nctx := t_multiply(1); 
        9  return ODCIConst.Success; 
        10 end; 
        11 
        12 member function ODCIAggregateIterate(self IN OUT t_multiply, 
        13          value IN number) 
        14 return number 
        15 is 
        16 
        17 begin 
        18 total := total * value; 
        19 return ODCIConst.Success; 
        20 end; 
        21 
        22 member function ODCIAggregateTerminate(self IN t_multiply, 
        23           retVal OUT number, 
        24           flags IN number) 
        25 return number 
        26 is 
        27 begin 
        28  retval := total; 
        29  return ODCIConst.Success; 
        30 end; 
        31 
        32 member function ODCIAggregateMerge(self IN OUT t_multiply, 
        33          ctx2 IN t_multiply) 
        34 return number 
        35 is 
        36 begin 
        37  return ODCIConst.Success; 
        38 end; 
        39 end; 
        40/
    
        Type body created 
    
        SQL> CREATE OR REPLACE FUNCTION multiply(input in number) 
        2 RETURN number 
        3 PARALLEL_ENABLE AGGREGATE USING t_multiply; 
        4/
    
        Function created 
    

    示範:

    SQL> with t1(col1, col2) as(
        2 select 1, 1 from dual union all 
        3 select 1, 2 from dual union all 
        4 select 1, 3 from dual union all 
        5 select 1, 4 from dual 
        6 ) 
        7 select col1 
        8  , sum(col2) over(partition by col1 order by col2) as sum1 
        9  , multiply(col2) over(partition by col1 order by col2) as mult 
        10 from t1 
        11 ; 
    
        COL1  SUM1  MULT 
        ---------- ---------- ---------- 
         1   1   1 
         1   3   2 
         1   6   6 
         1   10   24 
    
  2. 你可以使用示範條款,以達到期望的結果:

    SQL> with t1(col1, col2) as(
        2 select 1, 1 from dual union all 
        3 select 1, 2 from dual union all 
        4 select 1, 3 from dual union all 
        5 select 1, 4 from dual 
        6 ) 
        7 select c1 
        8  , col2 
        9  , mult 
        10 from t1 
        11 model 
        12 partition by (col1 as c1) 
        13 dimension by (row_number() over(order by col2) rn) 
        14 measures(col2, 1 as mult) 
        15 rules(
        16  mult[rn] = nvl(mult[cv() - 1], 1) * col2[cv()] 
        17 ) 
        18 ; 
    
        C1  COL2  MULT 
        ---------- ---------- ---------- 
        1   1   1 
        1   2   2 
        1   3   6 
        1   4   24 
    
1

爲了把@ DavidAldridge的建議爲代碼(並小心處理負值)可能看起來像這樣:

WITH T AS 
(
    SELECT 2 AS X FROM DUAL 
    UNION ALL 
    SELECT -3 AS X FROM DUAL 
    UNION ALL 
    SELECT 4 AS X FROM DUAL 
) 
SELECT 
    CASE 
     -- If there are any zeroes, then the result is zero. 
     WHEN MAX(CASE WHEN X = 0 THEN 1 END) > 0 THEN 0 
     -- Otherwise, if there is an even (or zero) number of 
     -- negative numbers, the result is positive. 
     WHEN MOD(COUNT(CASE WHEN X < 0 THEN 1 END), 2) = 0 THEN 1 
     -- Otherwise, the result is negative. 
     ELSE -1 
    END 
    * 
    EXP 
    (
     SUM 
     (
      CASE 
       WHEN X = 0 THEN 0 
       ELSE LN(ABS(X)) 
      END    
     ) 
    ) 
FROM 
    T; 

有一點要注意,雖然是有可能用這種方法比使用方法舍入誤差更大的風險(如通過@NicholasKrasnov建議那些的)直接用乘法。