Att göra tidsintervall, och speciellt att göra aggregationer (summor, medelvärden) över många intervall eller intervallgrupper är inte okomplicerat i Oracle. AVG-funktionen fungerar inte på tidsstämpelintervall, den förväntar sig siffror. Så vi måste skapa vårt eget aggregeringsobjekt och funktion som gör detta.
Först, objektspecifikationen :
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
);
Och objektkroppen :
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;
Slutligen, funktionen som använder ovanstående objekt :
CREATE OR REPLACE FUNCTION avg_interval( x DSINTERVAL_UNCONSTRAINED)
RETURN DSINTERVAL_UNCONSTRAINED PARALLEL_ENABLE
AGGREGATE USING AvgInterval;
Nu kan vi använda det så här :
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;
Utdata:
+00 02:00:00.562669
Vi kan också samla över grupper med detta :
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;
Utdata:
FL +00 01:32:35.000000
GA +00 01:01:00.000000