web-dev-qa-db-fra.com

Extraire le nombre total de secondes d'un type de données d'intervalle

Lors de la soustraction de timestamps, la valeur de retour est un type de données interval. Existe-t-il un moyen élégant de convertir cette valeur en nombre total (milli/micro) secondes dans l'intervalle, c'est-à-dire un entier.

Ce qui suit fonctionnerait, mais ce n'est pas très joli:

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 )

Existe-t-il une méthode plus élégante en SQL ou PL/SQL?

28
Ben

J'espère que cette aide:

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

Avec votre test:

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> 
20
zep

Un moyen simple:

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

L'idée est de convertir la valeur de l'intervalle en jours par fois 86400 (= 24 * 60 * 60). Ensuite, extrayez la valeur "jour" qui est en fait la deuxième valeur que nous voulions.

21
Zhaoping Lu

J'ai trouvé que ça fonctionnait. Apparemment, si vous faites des calculs avec des horodatages, ils sont convertis en un type de données interne qui, une fois soustrait les uns des autres, renvoie l'intervalle sous forme de nombre.

Facile? Oui. Élégant? Non. Fait le travail? Oh oui.

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

Malheureusement, je ne pense pas qu'il existe une manière alternative (ou plus élégante) de calculer le nombre total de secondes à partir d'un type d'intervalle en pl/sql. Comme cet article mentionne:

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

par conséquent, extraire le jour, l'heure, etc. de l'intervalle et les multiplier par des valeurs correspondantes semble être le seul moyen.

4
Korhan Ozturk

Basé sur réponse de zep , j'ai enveloppé les choses dans une fonction pour votre commodité:

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 ; 
2
Tomislav Matas

Utilisez la requête suivante:

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