Oracle
 sql >> Database >  >> RDS >> Oracle

Sottrarre le date in Oracle:tipo di dati numerico o intervallo?

Ok, normalmente non rispondo alle mie domande ma dopo un po' di armeggiare, ho capito definitivamente come Oracle memorizza il risultato di una sottrazione DATE.

Quando si sottraggono 2 date, il valore non è un tipo di dati NUMBER (come farebbe credere il manuale di riferimento SQL di Oracle 11.2). Il numero del tipo di dati interno di una sottrazione DATE è 14, che è un tipo di dati interno non documentato (NUMERO è il tipo di dati interno numero 2). Tuttavia, viene effettivamente memorizzato come 2 numeri separati con segno in complemento a due, con i primi 4 byte utilizzati per rappresentare il numero di giorni e gli ultimi 4 byte utilizzati per rappresentare il numero di secondi.

Un esempio di sottrazione DATE risultante in una differenza intera positiva:

select date '2009-08-07' - date '2008-08-08' from dual;

Risultati in:

DATE'2009-08-07'-DATE'2008-08-08'
---------------------------------
                              364

select dump(date '2009-08-07' - date '2008-08-08') from dual;

DUMP(DATE'2009-08-07'-DATE'2008
-------------------------------
Typ=14 Len=8: 108,1,0,0,0,0,0,0

Ricordiamo che il risultato è rappresentato come un complemento a due separato di 2 con numeri di 4 byte con segno. Poiché in questo caso non ci sono decimali (esattamente 364 giorni e 0 ore), gli ultimi 4 byte sono tutti 0 e possono essere ignorati. Per i primi 4 byte, poiché la mia CPU ha un'architettura little-endian, i byte vengono invertiti e dovrebbero essere letti come 1.108 o 0x16c, che è decimale 364.

Un esempio di sottrazione DATE risultante in una differenza intera negativa:

select date '1000-08-07' - date '2008-08-08' from dual;

Risultati in:

DATE'1000-08-07'-DATE'2008-08-08'
---------------------------------
                          -368160

select dump(date '1000-08-07' - date '2008-08-08') from dual;

DUMP(DATE'1000-08-07'-DATE'2008-08-0
------------------------------------
Typ=14 Len=8: 224,97,250,255,0,0,0,0

Ancora una volta, poiché sto usando una macchina little-endian, i byte sono invertiti e dovrebbero essere letti come 255,250,97,224 che corrisponde a 11111111 11111010 01100001 11011111. Ora, poiché questo è nella codifica numerica binaria con segno in complemento a due, sappiamo che il numero è negativo perché la cifra binaria più a sinistra è un 1. Per convertirlo in un numero decimale dovremmo invertire il complemento a 2 (sottrai 1 quindi esegui il complemento a uno) risultando in:00000000 00000101 10011110 00100000 che equivale a -368160 come sospettato.

Un esempio di sottrazione DATE risultante in una differenza decimale:

select to_date('08/AUG/2004 14:00:00', 'DD/MON/YYYY HH24:MI:SS'
 - to_date('08/AUG/2004 8:00:00', 'DD/MON/YYYY HH24:MI:SS') from dual;

TO_DATE('08/AUG/200414:00:00','DD/MON/YYYYHH24:MI:SS')-TO_DATE('08/AUG/20048:00:
--------------------------------------------------------------------------------
                                                                             .25

La differenza tra queste 2 date è di 0,25 giorni o 6 ore.

select dump(to_date('08/AUG/2004 14:00:00', 'DD/MON/YYYY HH24:MI:SS')
 - to_date('08/AUG/2004 8:00:00', 'DD/MON/YYYY HH24:MI:SS')) from dual;

DUMP(TO_DATE('08/AUG/200414:00:
-------------------------------
Typ=14 Len=8: 0,0,0,0,96,84,0,0

Ora questa volta, poiché la differenza è 0 giorni e 6 ore, ci si aspetta che i primi 4 byte siano 0. Per gli ultimi 4 byte, possiamo invertirli (perché la CPU è little-endian) e ottenere 84,96 =01010100 01100000 base 2 =21600 in decimale. La conversione di 21600 secondi in ore ti dà 6 ore, che è la differenza che ci aspettavamo.

Spero che questo aiuti chiunque si chiedesse come viene effettivamente memorizzata una sottrazione DATE.