Ervan uitgaande dat LAST_TRANSACTION_DATE
is een DATE
kolom (of TIMESTAMP
) dan zijn beide versies een zeer slechte gewoonte.
In beide gevallen de DATE
kolom wordt impliciet geconverteerd naar een letterlijke letter op basis van de huidige NLS-instellingen. Dat betekent dat je met verschillende klanten verschillende resultaten krijgt.
Bij gebruik van letterlijke datums altijd gebruik to_date()
met(!) een formaatmasker of gebruik een letterlijke ANSI-datum. Op die manier vergelijk je datums met datums en niet strings met strings. Dus voor de gelijke vergelijking moet je gebruiken:
LAST_TRANSACTION_DATE = to_date('30-JUL-07', 'dd-mon-yy')
Merk op dat het gebruik van 'MON' nog steeds kan leiden tot fouten met verschillende NLS-instellingen ('DEC'
vs. 'DEZ'
of 'MAR'
vs. 'MRZ'
). Het is veel minder foutgevoelig bij het gebruik van maandnummers (en viercijferige jaren):
LAST_TRANSACTION_DATE = to_date('30-07-2007', 'dd-mm-yyyy')
of een ANSI-datum letterlijk gebruiken
LAST_TRANSACTION_DATE = DATE '2007-07-30'
De reden waarom de bovenstaande query zeer waarschijnlijk niets zal opleveren, is dat in Oracle DATE
kolommen bevatten ook de tijd. De bovenstaande letterlijke datums bevatten impliciet de tijd 00:00
. Als de tijd in de tabel anders is (bijv. 19:54
) dan zijn de data natuurlijk niet gelijk.
Om dit probleem te omzeilen heeft u verschillende opties:
- gebruik
trunc()
in de tabelkolom om de tijd te "normaliseren" naar00:00
trunc(LAST_TRANSACTION_DATE) = DATE '2007-07-30
dit voorkomt echter het gebruik van een index gedefinieerd opLAST_TRANSACTION_DATE
- gebruik
between
LAST_TRANSACTION_DATE between to_date('2007-07-30 00:00:00', 'yyyy-mm-dd hh24:mi:ss') and to_date('2007-07-30 23:59:59', 'yyyy-mm-dd hh24:mi:ss')
Het prestatieprobleem van de eerste oplossing kan worden omzeild door een index te maken op trunc(LAST_TRANSACTION_DATE)
die door die uitdrukking zou kunnen worden gebruikt. Maar de uitdrukking LAST_TRANSACTION_DATE = '30-JUL-07'
voorkomt ook een indexgebruik omdat het intern wordt verwerkt als to_char(LAST_TRANSACTION_DATE) = '30-JUL-07'
De belangrijke dingen om te onthouden:
- Vertrouw nooit op impliciete conversie van gegevenstypes. Het zal op een gegeven moment problemen geven. Vergelijk altijd de juiste gegevenstypen
- Oracle
DATE
kolommen bevatten altijd een tijd die deel uitmaakt van de vergelijkingsregels.