我有一个如下所示的查询:
SELECT SUM(CAPITAL_RETURN) OVER (PARTITION BY PORTF_CODE,
EXTRACT(MONTH FROM END_DATE) ORDER BY END_DATE
) AS CUM_CAPITAL_RET,
FROM
....
这适用于创建累积和列,但我现在需要创建一个累积乘法列。
这可能吗?
由于
答案 0 :(得分:2)
您可以编写用户定义的聚合函数。这是一个例子:
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
您可以使用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建议的那些)。