plsql累积乘法

时间:2012-11-29 11:35:49

标签: oracle plsql

我有一个如下所示的查询:

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

这适用于创建累积和列,但我现在需要创建一个累积乘法列。

这可能吗?

由于

3 个答案:

答案 0 :(得分: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. 您可以使用model子句来实现所需的结果:

     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 :(得分:1)

这样做的经典方法是取值的对数之和的指数,注意正确处理负数零。

答案 2 :(得分: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建议的那些)。