Ok, normaal beantwoord ik mijn eigen vragen niet, maar na wat knutselen ben ik er definitief achter hoe Oracle het resultaat van een DATE-aftrekking opslaat.
Als u 2 datums aftrekt, is de waarde geen NUMBER-gegevenstype (zoals de Oracle 11.2 SQL Reference-handleiding u zou doen geloven). Het interne datatypenummer van een DATE-aftrekking is 14, wat een niet-gedocumenteerd intern datatype is (NUMBER is intern datatypenummer 2). Het wordt echter in feite opgeslagen als 2 aparte getallen met twee complementaire tekens, waarbij de eerste 4 bytes het aantal dagen vertegenwoordigen en de laatste 4 bytes het aantal seconden.
Een voorbeeld van een DATE-aftrekking die resulteert in een positief geheel getal verschil:
select date '2009-08-07' - date '2008-08-08' from dual;
Resultaten 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
Bedenk dat het resultaat wordt weergegeven als een 2-complement van twee afzonderlijke twee, ondertekende getallen van 4 bytes. Aangezien er in dit geval geen decimalen zijn (precies 364 dagen en 0 uur), zijn de laatste 4 bytes allemaal nullen en kunnen ze worden genegeerd. Voor de eerste 4 bytes, omdat mijn CPU een little-endian-architectuur heeft, zijn de bytes omgekeerd en moeten ze worden gelezen als 1.108 of 0x16c, wat decimaal 364 is.
Een voorbeeld van een DATE-aftrekking die resulteert in een negatief geheel getal verschil:
select date '1000-08-07' - date '2008-08-08' from dual;
Resultaten 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
Nogmaals, aangezien ik een little-endian-machine gebruik, zijn de bytes omgekeerd en moeten ze worden gelezen als 255,250,97,224 wat overeenkomt met 11111111 11111010 01100001 11011111. Omdat dit nu in two's complement ondertekende binaire cijfercodering is, weten we dat het nummer is negatief omdat het meest linkse binaire cijfer een 1 is. Om dit om te zetten in een decimaal getal zouden we het complement van de 2 moeten omkeren (aftrekken 1 en dan het complement van de ene doen), wat resulteert in:00000000 00000101 10011110 00100000 wat gelijk is aan -368160 zoals vermoed.
Een voorbeeld van een DATE-aftrekking die resulteert in een decimaal verschil:
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
Het verschil tussen die 2 datums is 0,25 dagen of 6 uur.
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
Deze keer, aangezien het verschil 0 dagen en 6 uur is, wordt verwacht dat de eerste 4 bytes 0 zijn. Voor de laatste 4 bytes kunnen we ze omkeren (omdat de CPU little-endian is) en krijgen 84,96 =01010100 01100000 basis 2 =21600 in decimalen. Als u 21600 seconden naar uren converteert, krijgt u 6 uur en dat is het verschil dat we verwachtten.
Ik hoop dat dit iedereen helpt die zich afvroeg hoe een DATE-aftrekking eigenlijk wordt opgeslagen.