Oracleでは、時間間隔を実行すること、特に多くの間隔または間隔グループにわたって集計(合計、平均)を実行することは簡単ではありません。 AVG関数はタイムスタンプ間隔では機能せず、数値を想定しています。したがって、これを行う独自の集計オブジェクトと関数を作成する必要があります。
まず、オブジェクトの仕様 :
CREATE OR REPLACE TYPE AvgInterval
AS OBJECT (
runningSum INTERVAL DAY(9) TO SECOND(9),
runningCnt number,
STATIC FUNCTION ODCIAggregateInitialize
( actx IN OUT AvgInterval
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate
( self IN OUT AvgInterval,
val IN DSINTERVAL_UNCONSTRAINED
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate
( self IN AvgInterval,
returnValue OUT DSINTERVAL_UNCONSTRAINED,
flags IN NUMBER
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge
(self IN OUT AvgInterval,
ctx2 IN AvgInterval
) RETURN NUMBER
);
そしてオブジェクト本体 :
CREATE OR REPLACE TYPE BODY AvgInterval AS
STATIC FUNCTION ODCIAggregateInitialize
( actx IN OUT AvgInterval
) RETURN NUMBER IS
BEGIN
IF actx IS NULL THEN
actx := AvgInterval (INTERVAL '0 0:0:0.0' DAY TO SECOND, 0);
ELSE
actx.runningSum := INTERVAL '0 0:0:0.0' DAY TO SECOND;
actx.runningCnt := 0;
END IF;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate
( self IN OUT AvgInterval,
val IN DSINTERVAL_UNCONSTRAINED
) RETURN NUMBER IS
BEGIN
self.runningSum := self.runningSum + val;
self.runningCnt := self.runningCnt + 1;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate
( self IN AvgInterval,
ReturnValue OUT DSINTERVAL_UNCONSTRAINED,
flags IN NUMBER
) RETURN NUMBER IS
BEGIN
if (runningCnt <> 0) then
returnValue := (self.runningSum/runningCnt);
else
returnValue := self.runningSum;
end if;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge
(self IN OUT AvgInterval,
ctx2 IN AvgInterval
) RETURN NUMBER IS
BEGIN
self.runningSum := self.runningSum + ctx2.runningSum;
self.runningCnt := self.runningCnt + ctx2.runningCnt;
RETURN ODCIConst.Success;
END;
END;
最後に、関数 上記のオブジェクトを使用する :
CREATE OR REPLACE FUNCTION avg_interval( x DSINTERVAL_UNCONSTRAINED)
RETURN DSINTERVAL_UNCONSTRAINED PARALLEL_ENABLE
AGGREGATE USING AvgInterval;
これで、使用できるようになりました このように :
with x as (
select systimestamp - 1/24 as created_date, systimestamp as modified_date from dual
union
select systimestamp - 2/24 as created_date, systimestamp as modified_date from dual
union
select systimestamp - 3/24 as created_date, systimestamp as modified_date from dual
)
select avg_interval(modified_date - created_date)
from x;
出力:
+00 02:00:00.562669
グループ全体を集約することもできます これで :
with x as (
select 'FL' as state, to_dsinterval('0 00:56:30') as duration from dual
union
select 'FL' as state, to_dsinterval('0 02:08:40') as duration from dual
union
select 'GA' as state, to_dsinterval('0 01:01:00') as duration from dual
)
select state, avg_interval(duration)
from x
group by state;
出力:
FL +00 01:32:35.000000
GA +00 01:01:00.000000