Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Datumsangaben in Oracle subtrahieren - Zahlen- oder Intervalldatentyp?

Ok, normalerweise beantworte ich meine eigenen Fragen nicht, aber nach ein bisschen Herumbasteln habe ich definitiv herausgefunden, wie Oracle das Ergebnis einer DATE-Subtraktion speichert.

Wenn Sie 2 Daten subtrahieren, ist der Wert kein NUMBER-Datentyp (wie Sie im Oracle 11.2 SQL Reference-Handbuch glauben machen). Die interne Datentypnummer einer DATE-Subtraktion ist 14, was ein nicht dokumentierter interner Datentyp ist (NUMBER ist die interne Datentypnummer 2). Es wird jedoch tatsächlich als 2 separate Zweierkomplement-Zahlen mit Vorzeichen gespeichert, wobei die ersten 4 Bytes verwendet werden, um die Anzahl der Tage darzustellen, und die letzten 4 Bytes, die verwendet werden, um die Anzahl der Sekunden darzustellen.

Ein Beispiel für eine DATE-Subtraktion, die zu einer positiven ganzzahligen Differenz führt:

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

Ergebnisse 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

Erinnern Sie sich, dass das Ergebnis als 2 getrennte Zweierkomplement-vorzeichenbehaftete 4-Byte-Zahlen dargestellt werden. Da es in diesem Fall keine Dezimalstellen gibt (genau 364 Tage und 0 Stunden), sind die letzten 4 Bytes alle 0 und können ignoriert werden. Da meine CPU eine Little-Endian-Architektur hat, sind die ersten 4 Bytes umgekehrt und sollten als 1.108 oder 0x16c gelesen werden, was dezimal 364 ist.

Ein Beispiel für eine DATE-Subtraktion, die zu einer negativen ganzzahligen Differenz führt:

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

Ergebnisse 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

Da ich eine Little-Endian-Maschine verwende, sind die Bytes umgekehrt und sollten als 255.250.97.224 gelesen werden, was 11111111 11111010 01100001 11011111 entspricht. Da dies nun im Zweierkomplement ist, wissen wir, dass die Zahl ist negativ, weil die Binärziffer ganz links eine 1 ist. Um dies in eine Dezimalzahl umzuwandeln, müssten wir das 2er-Komplement umkehren (subtrahieren Sie 1, dann machen Sie das Einer-Komplement), was zu:00000000 00000101 10011110 00100000 führt, was -368160 entspricht, wie vermutet.

Ein Beispiel für eine DATE-Subtraktion, die zu einer Dezimaldifferenz führt:

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

Der Unterschied zwischen diesen 2 Daten beträgt 0,25 Tage oder 6 Stunden.

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

Da die Differenz diesmal 0 Tage und 6 Stunden beträgt, wird erwartet, dass die ersten 4 Bytes 0 sind. Für die letzten 4 Bytes können wir sie umkehren (weil die CPU Little-Endian ist) und erhalten 84,96 =01010100 01100000 Basis 2 =21600 in Dezimalzahl. Wenn Sie 21600 Sekunden in Stunden umrechnen, erhalten Sie 6 Stunden, was die Differenz ist, die wir erwartet haben.

Ich hoffe, das hilft allen, die sich gefragt haben, wie eine DATE-Subtraktion tatsächlich gespeichert wird.