我有一個查詢,看起來像這樣:PLSQL累積乘法
SELECT SUM(CAPITAL_RETURN) OVER (PARTITION BY PORTF_CODE,
EXTRACT(MONTH FROM END_DATE) ORDER BY END_DATE
) AS CUM_CAPITAL_RET,
FROM
....
這是罰款創建累積和列,但我現在需要創建一個累積乘法列。
這可能嗎?
感謝
我有一個查詢,看起來像這樣:PLSQL累積乘法
SELECT SUM(CAPITAL_RETURN) OVER (PARTITION BY PORTF_CODE,
EXTRACT(MONTH FROM END_DATE) ORDER BY END_DATE
) AS CUM_CAPITAL_RET,
FROM
....
這是罰款創建累積和列,但我現在需要創建一個累積乘法列。
這可能嗎?
感謝
做的傳統方式,這是通過取值的對數的總和的指數,同時注意正確處理底片零。
您可以編寫用戶定義的聚合函數。這裏有一個例子:
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
你可以使用示範條款,以達到期望的結果:
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
爲了把@ 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建議那些的)直接用乘法。