SQL:是否可以使用INTERVAL类型的SUM()字段?

时间:2010-07-28 10:43:39

标签: sql-server oracle tsql plsql date-arithmetic

我想把INTERVAL加起来。 E.g。

SELECT SUM(TIMESTAMP1 - TIMESTAMP2) FROM DUAL

是否可以编写可在Oracle和SQL Server上运行的查询?如果是这样,怎么样?

编辑:将DATE更改为INTERVAL

7 个答案:

答案 0 :(得分:6)

我担心你会在运行Oracle和MSSQL的解决方案中运气不好。日期算术在DBMS的各种风格上是非常不同的。

无论如何,在Oracle中我们可以在简单的算术中使用日期。我们有一个函数NUMTODSINTERVAL,它将数字转换为DAY TO SECOND INTERVAL。所以我们把它们组合在一起。

简单的测试数据,两行,成对日期相隔十二小时:

SQL> alter session set nls_date_format = 'dd-mon-yyyy hh24:mi:ss'
  2  /

Session altered.

SQL> select * from t42
  2  /

D1                   D2
-------------------- --------------------
27-jul-2010 12:10:26 27-jul-2010 00:00:00
28-jul-2010 12:10:39 28-jul-2010 00:00:00

SQL>

简单SQL查询以查找已用时间的总和:

SQL> select numtodsinterval(sum(d1-d2), 'DAY')
  2  from t42
  3  /

NUMTODSINTERVAL(SUM(D1-D2),'DAY')
-----------------------------------------------------
+000000001 00:21:04.999999999

SQL>

只需一天,这就是我们所期望的。


  

“编辑:将日期更改为INTERVAL”

使用TIMESTAMP列更加繁琐,但我们仍然可以使用相同的技巧。

在以下示例中。 T42T与T42相同,只有列具有TIMESTAMP而不是DATE作为其数据类型。查询提取DS INTERVAL的各种组件并将它们转换为秒,然后将它们相加并转换回INTERVAL:

SQL> select numtodsinterval(
  2              sum(
  3                  extract (day from (t1-t2)) * 86400
  4                   + extract (hour from (t1-t2)) * 3600
  5                   + extract (minute from (t1-t2)) * 600
  6                   + extract (second from (t1-t2))
  7            ), 'SECOND')
  8  from t42t
  9  /

NUMTODSINTERVAL(SUM(EXTRACT(DAYFROM(T1-T2))*86400+EXTRACT(HOURFROM(T1-T2))*
---------------------------------------------------------------------------
+000000001 03:21:05.000000000

SQL>

至少这个结果是在几秒钟内完成的!

答案 1 :(得分:5)

好的,经过一段时间的地狱,借助stackoverflowers的答案,我找到了符合我需求的解决方案。


SELECT
  SUM(CAST((DATE1 + 0) - (DATE2 + 0) AS FLOAT) AS SUM_TURNAROUND
FROM MY_BEAUTIFUL_TABLE
GROUP BY YOUR_CHOSEN_COLUMN

这会返回一个浮点数(对我来说完全没问题),它代表Oracle ant SQL Server上的几天。

我向两个DATE添加零的原因是因为在我的情况下,Oracle DB上的日期列是TIMESTAMP类型,而SQL Server上的日期列是DATETIME类型(这显然是很奇怪)。因此,在Oracle上向TIMESTAMP添加零就像生成日期一样,它对SQL Server DATETIME类型没有任何影响。

谢谢你们!你真的很有帮助。

答案 2 :(得分:3)

您不能将两个日期时间相加。这没有意义 - 即15:00:00加23:59:00等于什么?第二天的某个时间?等

但是您可以使用SQL Server中的Dateadd()函数添加时间增量。

答案 3 :(得分:3)

在SQL Server中,只要您的个人时间跨度小于24小时,您就可以执行类似

的操作
WITH TIMES AS
(
SELECT CAST('01:01:00' AS DATETIME) AS TimeSpan
UNION ALL
SELECT '00:02:00'
UNION ALL
SELECT '23:02:00'
UNION ALL
SELECT '17:02:00'
--UNION ALL SELECT '24:02:00' /*This line would fail!*/
),
SummedTimes As
(
SELECT cast(SUM(CAST(TimeSpan AS FLOAT)) as datetime) AS [Summed] FROM TIMES
)
SELECT 
    FLOOR(CAST(Summed AS FLOAT)) AS D,
    DATEPART(HOUR,[Summed]) AS H,
    DATEPART(MINUTE,[Summed]) AS M,
    DATEPART(SECOND,[Summed]) AS S
FROM SummedTimes

给出

D           H           M           S
----------- ----------- ----------- -----------
1           17          7           0

如果您想处理超过24小时的时间跨度,我认为您需要查看CLR集成和TimeSpan结构。绝对不便携!

编辑:SQL Server 2008有一个DateTimeOffset数据类型可能有所帮助,但不允许SUM ming或被强制转换为

答案 4 :(得分:0)

我也不认为这是可能的。使用根据您的偏好计算日期值的自定义解决方案。

答案 5 :(得分:0)

您也可以使用:

select  
  EXTRACT (DAY FROM call_end_Date - call_start_Date)*86400 + 
  EXTRACT (HOUR FROM call_end_Date - call_start_Date)*3600 + 
  EXTRACT (MINUTE FROM call_end_Date - call_start_Date)*60 + 
  extract (second FROM call_end_Date - call_start_Date) as interval
from table;

答案 6 :(得分:0)

你可以写自己的聚合函数:-)。请仔细阅读http://docs.oracle.com/cd/B19306_01/appdev.102/b14289/dciaggfns.htm

您必须按模板创建对象类型及其主体,然后使用此对象创建下一个聚合函数:

create or replace type Sum_Interval_Obj as object
(
  -- Object for creating and support custom aggregate function
  duration interval day to second, -- In this property You sum all interval

  -- Object Init
  static function ODCIAggregateInitialize(
    actx IN OUT Sum_Interval_Obj
    ) return number,

  -- Iterate getting values from dataset 
  member function ODCIAggregateIterate(
    self         IN OUT  Sum_Interval_Obj,
    ad_interval  IN  interval day to second
    ) return number,

  -- Merge parallel summed data
  member function ODCIAggregateMerge(
    self IN OUT Sum_Interval_Obj,
    ctx2 IN Sum_Interval_Obj
  ) return number,

  -- End of query, returning summary result
  member function ODCIAggregateTerminate
  (
    self        IN  Sum_Interval_Obj,
    returnValue OUT interval day to second,
    flags       IN number
  ) return number

)
/

create or replace type body Sum_Interval_Obj is

  -- Object Init
  static function ODCIAggregateInitialize(
    actx IN OUT Sum_Interval_Obj
    ) return number
    is
  begin
    actx := Sum_Interval_Obj(numtodsinterval(0,'SECOND'));
    return ODCIConst.Success;
  end ODCIAggregateInitialize;

  -- Iterate getting values from dataset 
  member function ODCIAggregateIterate(
    self         IN OUT Sum_Interval_Obj,
    ad_interval  IN interval day to second
    ) return number
    is
  begin
    self.duration := self.duration + ad_interval; 
    return ODCIConst.Success;
  exception
    when others then
      return ODCIConst.Error;
  end ODCIAggregateIterate;

  -- Merge parallel calculated intervals
  member function ODCIAggregateMerge(
    self IN OUT Sum_Interval_Obj,
    ctx2 IN     Sum_Interval_Obj
    ) return number
    is
  begin
    self.duration := self.duration + ctx2.duration; -- Add two intervals
    -- return = All Ok!
    return ODCIConst.Success;
  exception
    when others then
      return ODCIConst.Error;
  end ODCIAggregateMerge;

  -- End of query, returning summary result
  member function ODCIAggregateTerminate(
    self        IN  Sum_Interval_Obj,
    returnValue OUT interval day to second,
    flags       IN number
    ) return number
    is
  begin
    -- return = All Ok, too!
    returnValue := self.duration;
    return ODCIConst.Success;
  end ODCIAggregateTerminate;

end;
/

-- You own new aggregate function:
CREATE OR REPLACE FUNCTION Sum_Interval(
    a_Interval interval day to second
    ) RETURN interval day to second
    PARALLEL_ENABLE AGGREGATE USING Sum_Interval_Obj;
/

最后,检查你的功能:

select sum_interval(duration)
  from (select numtodsinterval(1,'SECOND')  as duration from dual union all
        select numtodsinterval(1,'MINUTE')  as duration from dual union all
        select numtodsinterval(1,'HOUR')    as duration from dual union all
        select numtodsinterval(1,'DAY')     as duration from dual);

最后,如果需要,可以创建SUM函数。