从间隔数据类型中提取总秒数

时间:2012-04-10 15:48:27

标签: sql oracle plsql

当减去timestamps时,返回值是interval数据类型。是否有一种优雅的方法可以将此值转换为区间中的总(毫秒/微秒),即整数。

以下可行,但不是很漂亮:

select abs( extract( second from interval_difference ) 
          + extract( minute from interval_difference ) * 60 
          + extract( hour from interval_difference ) * 60 * 60 
          + extract( day from interval_difference ) * 60 * 60 * 24
            )
  from ( select systimestamp - (systimestamp - 1) as interval_difference
           from dual )

SQL或PL / SQL中是否有更优雅的方法?

9 个答案:

答案 0 :(得分:21)

一种简单的方法:

select extract(day from (ts1-ts2)*86400) from dual;

我们的想法是将间隔值转换为天数86400(= 24 * 60 * 60)。 然后提取'day'值,这实际上是我们想要的第二个值。

答案 1 :(得分:20)

我希望这有帮助:

zep@dev> select interval_difference
      2        ,sysdate + (interval_difference * 86400) - sysdate as fract_sec_difference
      3  from   (select systimestamp - (systimestamp - 1) as interval_difference
      4          from   dual)
      5 ;

INTERVAL_DIFFERENCE                                                             FRACT_SEC_DIFFERENCE
------------------------------------------------------------------------------- --------------------
+000000001 00:00:00.375000                                                                 86400,375

通过测试:

zep@dev> select interval_difference
      2        ,abs(extract(second from interval_difference) +
      3        extract(minute from interval_difference) * 60 +
      4        extract(hour from interval_difference) * 60 * 60 +
      5        extract(day from interval_difference) * 60 * 60 * 24) as your_sec_difference
      6        ,sysdate + (interval_difference * 86400) - sysdate as fract_sec_difference
      7        ,round(sysdate + (interval_difference * 86400) - sysdate) as sec_difference
      8        ,round((sysdate + (interval_difference * 86400) - sysdate) * 1000) as millisec_difference
      9  from   (select systimestamp - (systimestamp - 1) as interval_difference
     10          from   dual)
     11  /

INTERVAL_DIFFERENCE                                                             YOUR_SEC_DIFFERENCE FRACT_SEC_DIFFERENCE SEC_DIFFERENCE MILLISEC_DIFFERENCE
------------------------------------------------------------------------------- ------------------- -------------------- -------------- -------------------
+000000001 00:00:00.515000                                                                86400,515            86400,515          86401            86400515

zep@dev> 

答案 2 :(得分:9)

我发现这个有用。显然,如果你使用时间戳进行算术运算,它们会转换为某种内部数据类型,当相互减去时,会将间隔作为数字返回。

容易吗?是。优雅?没有。完成工作?哦是的。

SELECT ( (A + 0) - (B + 0) ) * 24 * 60 * 60 
FROM
(
   SELECT SYSTIMESTAMP A,
          SYSTIMESTAMP - INTERVAL '1' MINUTE B
   FROM DUAL
);

答案 3 :(得分:4)

不幸的是,我不认为有一种替代(或更优雅)的方法来计算pl / sql中间隔类型的总秒数。正如this article提到:

... unlike .NET, Oracle provides no simple equivalent to TimeSpan.TotalSeconds.

因此从区间中提取日,小时等并将它们与相应的值相乘似乎是唯一的方法。

答案 4 :(得分:2)

基于zep's answer,为方便起见,我将内容整理成一个函数:

CREATE OR REPLACE FUNCTION intervalToSeconds( 
     pMinuend TIMESTAMP , pSubtrahend TIMESTAMP ) RETURN NUMBER IS

vDifference INTERVAL DAY TO SECOND ; 

vSeconds NUMBER ;

BEGIN 

vDifference := pMinuend - pSubtrahend ;

SELECT EXTRACT( DAY    FROM vDifference ) * 86400
     + EXTRACT( HOUR   FROM vDifference ) *  3600
     + EXTRACT( MINUTE FROM vDifference ) *    60
     + EXTRACT( SECOND FROM vDifference )
  INTO
    vSeconds 
  FROM DUAL ;

  RETURN vSeconds ;

END intervalToSeconds ; 

答案 5 :(得分:1)

使用以下查询:

select (cast(timestamp1 as date)-cast(timestamp2 as date))*24*60*60)

答案 6 :(得分:0)

类似于@Zhaoping Lu的答案,但直接提取秒而不是从天数中获取秒。

SELECT extract(second from (end_date - start_date)) as "Seconds number"
FROM my_table

(在PostgresSQL 9.6.1上工作)

答案 7 :(得分:-1)

将时间戳转换为纳秒的更短方法。

SELECT (EXTRACT(DAY FROM (
    SYSTIMESTAMP --Replace line with desired timestamp --Maximum value: TIMESTAMP '3871-04-29 10:39:59.999999999 UTC'
- TIMESTAMP '1970-01-01 00:00:00 UTC') * 24 * 60) * 60 + EXTRACT(SECOND FROM
    SYSTIMESTAMP --Replace line with desired timestamp
)) *  1000000000 AS NANOS FROM DUAL;

NANOS
1598434427263027000

一种将纳秒转换为时间戳的方法。

SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
    1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS TIMESTAMP FROM dual;

TIMESTAMP
26/08/20 09:33:47,263027000 UTC

如预期的那样,上述方法的结果不受时区的影响。

一种将间隔转换为纳秒的较短方法。

SELECT (EXTRACT(DAY FROM (
    INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval --Maximum value: INTERVAL '+694444 10:39:59.999999999' DAY(6) TO SECOND(9) or up to 3871 year
) * 24 * 60) * 60 + EXTRACT(SECOND FROM (
    INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval
))) * 1000000000 AS NANOS FROM DUAL;

NANOS
1598434427263027000

一种将纳秒转换为间隔的方法。

SELECT numtodsinterval(
    1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS INTERVAL FROM dual;

INTERVAL
+18500 09:33:47.263027

例如,如果要使用毫秒而不是纳秒,则将1000000000替换为1000。

我已经尝试了一些发布的方法,但是在将间隔乘以86400时遇到了一个异常“ ORA-01873:间隔的前导精度太小”,所以我决定发布一种有效的方法为我。

答案 8 :(得分:-2)

选择to_char(ENDTIME,'yyyymmddhh24missff')-to_char(STARTTIME,'yyyymmddhh24missff')AS DUR 从双; yyyymmddhh24miss-将提供SEC的持续时间 yyyymmddhh24mi持续时间(分钟) yyyymmddhh24-持续时间-小时 yyyymmdd天数持续时间