How to average time intervals?

后端 未结 6 1086
故里飘歌
故里飘歌 2020-12-09 17:03

In Oracle 10g I have a table that holds timestamps showing how long certain operations took. It has two timestamp fields: starttime and endtime. I want to find averages of t

6条回答
  •  一整个雨季
    2020-12-09 17:40

    SQL Fiddle

    Oracle 11g R2 Schema Setup:

    Create a type to use when performing a custom aggregation:

    CREATE TYPE IntervalAverageType AS OBJECT(
      total INTERVAL DAY(9) TO SECOND(9),
      ct    INTEGER,
    
      STATIC FUNCTION ODCIAggregateInitialize(
        ctx         IN OUT IntervalAverageType
      ) RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateIterate(
        self        IN OUT IntervalAverageType,
        value       IN     INTERVAL DAY TO SECOND
      ) RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateTerminate(
        self        IN OUT IntervalAverageType,
        returnValue    OUT INTERVAL DAY TO SECOND,
        flags       IN     NUMBER
      ) RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateMerge(
        self        IN OUT IntervalAverageType,
        ctx         IN OUT IntervalAverageType
      ) RETURN NUMBER
    );
    /
    
    CREATE OR REPLACE TYPE BODY IntervalAverageType
    IS
      STATIC FUNCTION ODCIAggregateInitialize(
        ctx         IN OUT IntervalAverageType
      ) RETURN NUMBER
      IS
      BEGIN
        ctx := IntervalAverageType( INTERVAL '0' DAY, 0 );
        RETURN ODCIConst.SUCCESS;
      END;
    
      MEMBER FUNCTION ODCIAggregateIterate(
        self        IN OUT IntervalAverageType,
        value       IN     INTERVAL DAY TO SECOND
      ) RETURN NUMBER
      IS
      BEGIN
        IF value IS NOT NULL THEN
          self.total := self.total + value;
          self.ct    := self.ct + 1;
        END IF;
        RETURN ODCIConst.SUCCESS;
      END;
    
      MEMBER FUNCTION ODCIAggregateTerminate(
        self        IN OUT IntervalAverageType,
        returnValue    OUT INTERVAL DAY TO SECOND,
        flags       IN     NUMBER
      ) RETURN NUMBER
      IS
      BEGIN
        IF self.ct = 0 THEN
          returnValue := NULL;
        ELSE
          returnValue := self.total / self.ct;
        END IF;
        RETURN ODCIConst.SUCCESS;
      END;
    
      MEMBER FUNCTION ODCIAggregateMerge(
        self        IN OUT IntervalAverageType,
        ctx         IN OUT IntervalAverageType
      ) RETURN NUMBER
      IS
      BEGIN
        self.total := self.total + ctx.total;
        self.ct    := self.ct + ctx.ct;
        RETURN ODCIConst.SUCCESS;
      END;
    END;
    /
    

    Then you can create a custom aggregation function:

    CREATE FUNCTION AVERAGE( difference INTERVAL DAY TO SECOND )
    RETURN INTERVAL DAY TO SECOND
    PARALLEL_ENABLE AGGREGATE USING IntervalAverageType;
    /
    

    Query 1:

    WITH INTERVALS( diff ) AS (
      SELECT INTERVAL '0' DAY FROM DUAL UNION ALL
      SELECT INTERVAL '1' DAY FROM DUAL UNION ALL
      SELECT INTERVAL '-1' DAY FROM DUAL UNION ALL
      SELECT INTERVAL '8' HOUR FROM DUAL UNION ALL
      SELECT NULL FROM DUAL
    )
    SELECT AVERAGE( diff ) FROM intervals
    

    Results:

    | AVERAGE(DIFF) |
    |---------------|
    |     0 2:0:0.0 |
    

提交回复
热议问题