Erstens ist mir bewusst, dass diese Frage im Allgemeinen Equals (=) vs. LIKE gestellt wurde . Hier erkundige ich mich nach Datumstypdaten in der ORACLE-Datenbank, ich fand folgendes, wenn ich auf diese Weise Statement auswähle:
%Vor% Ich bekomme alle Zeilen, nach denen ich suche. aber wenn ich stattdessen das Zeichen gleich =
verwende:
Ich bekomme nichts, obwohl nichts anders ist als das Gleichheitszeichen. Kann ich bitte eine Erklärung dafür finden?
Wenn LAST_TRANSACTION_DATE
eine DATE
-Spalte (oder TIMESTAMP
) ist, sind beide Versionen sehr schlecht.
In beiden Fällen wird die Spalte DATE
implizit in ein Zeichenliteral konvertiert, das auf den aktuellen NLS-Einstellungen basiert. Das bedeutet, dass Sie bei verschiedenen Kunden unterschiedliche Ergebnisse erhalten.
Wenn Sie Datumsliterale verwenden immer verwenden Sie to_date()
mit (!) einer Formatmaske oder verwenden Sie ein ANSI-Datumsliteral. Auf diese Weise vergleichen Sie Datumsangaben mit Datumsangaben nicht mit Zeichenfolgen. Also für den gleichen Vergleich sollten Sie verwenden:
Beachten Sie, dass die Verwendung von "MON" immer noch zu Fehlern mit unterschiedlichen NLS-Einstellungen führen kann ( 'DEC'
vs. 'DEZ'
oder 'MAR'
vs. 'MRZ'
). Es ist viel weniger fehleranfällig mit Monatszahlen (und vierstelligen Jahren):
oder mithilfe eines ANSI-Datumsliterals
%Vor% Nun ist der Grund, warum die obige Abfrage sehr wahrscheinlich nichts zurückgibt, dass in Oracle DATE
Spalten auch die Zeit enthält. Die obigen Datumsliterale enthalten implizit die Zeit 00:00
. Wenn die Zeit in der Tabelle unterschiedlich ist (z. B. 19:54
), sind die Daten natürlich nicht gleich.
Um dieses Problem zu umgehen, haben Sie verschiedene Möglichkeiten:
trunc()
in der Tabellenspalte, um die Zeit in 00:00
zu "normalisieren"
%Code%
Dies verhindert jedoch die Verwendung eines Indexes, der für trunc(LAST_TRANSACTION_DATE) = DATE '2007-07-30
definiert wurde.
LAST_TRANSACTION_DATE
between
Das Leistungsproblem der ersten Lösung könnte umgangen werden, indem ein Index für 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')
erstellt wird, der von diesem Ausdruck verwendet werden könnte. Der Ausdruck trunc(LAST_TRANSACTION_DATE)
verhindert jedoch auch eine Indexverwendung, da er intern als LAST_TRANSACTION_DATE = '30-JUL-07'
Die wichtigen Dinge zu erinnern:
to_char(LAST_TRANSACTION_DATE) = '30-JUL-07'
Spalten enthalten immer eine Zeit, die Teil der Vergleichsregeln ist. Sie sollten ein Datum nicht direkt mit einer Zeichenfolge vergleichen. Sie verlassen sich auf implizite Conversions , deren Regeln schwer zu merken sind .
Außerdem ist Ihr Datumsformat nicht optimal gewählt: Jahre haben vier Ziffern (Y2K-Bug?), und nicht alle Sprachen haben den siebten Monat des Jahres mit dem Namen JUL
. Sie sollten etwas wie YYYY/MM/DD
verwenden.
Schließlich sind Datumsangaben in Oracle zeitlich genau auf die Sekunde genau. Alle Datumsangaben haben eine Zeitkomponente , auch wenn es sich um 00:00:00
handelt. Wenn Sie den Operator =
verwenden, vergleicht Oracle Datum und Uhrzeit für Datumsangaben.
Hier ist ein Testfall, der das von Ihnen beschriebene Verhalten wiedergibt:
%Vor% Wenn Sie den Operator =
verwenden, konvertiert Oracle die konstante Zeichenkette 30-JUL-07
in ein Datum und vergleicht den Wert mit der Spalte wie folgt:
Wenn Sie den Operator LIKE
verwenden, konvertiert Oracle die Spalte in eine Zeichenfolge und vergleicht sie mit der rechten Seite, was äquivalent ist zu:
Vergleichen Sie immer Datumsangaben mit Daten und Zeichenfolgen mit Zeichenfolgen. Verwandte Frage:
Das Datumsfeld ist keine Zeichenfolge. Intern wird eine implizite Konvertierung in eine Zeichenfolge ausgeführt, wenn Sie =
verwenden, die keiner Übereinstimmung entspricht, da Ihre Zeichenfolge nicht die erforderliche Genauigkeit aufweist.
Ich würde annehmen, dass sich die LIKE
-Anweisung in einem Datumsfeld etwas anders verhält, wodurch implizite Platzhalter im Vergleich verwendet werden, die die Genauigkeit überflüssig machen. Im Wesentlichen funktioniert Ihr LIKE
folgendermaßen: