Gleich (=) vs. LIKE für Datumsdatentyp

8

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:

%Vor%

Ich bekomme nichts, obwohl nichts anders ist als das Gleichheitszeichen. Kann ich bitte eine Erklärung dafür finden?

    
Hawk 29.08.2013, 07:59
quelle

3 Antworten

14

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:

%Vor%

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):

%Vor%

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:

  1. Verwenden Sie 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.
  2. benutze 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'

verarbeitet wird

Die wichtigen Dinge zu erinnern:

  1. Verlassen Sie sich niemals auf eine implizite Datentypkonvertierung. Es wird Ihnen irgendwann Probleme bereiten. Vergleichen Sie immer die richtigen Datentypen
  2. Oracle to_char(LAST_TRANSACTION_DATE) = '30-JUL-07' Spalten enthalten immer eine Zeit, die Teil der Vergleichsregeln ist.
a_horse_with_no_name 29.08.2013, 08:23
quelle
6

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:

%Vor%

Wenn Sie den Operator LIKE verwenden, konvertiert Oracle die Spalte in eine Zeichenfolge und vergleicht sie mit der rechten Seite, was äquivalent ist zu:

%Vor%

Vergleichen Sie immer Datumsangaben mit Daten und Zeichenfolgen mit Zeichenfolgen. Verwandte Frage:

Vincent Malgrat 29.08.2013 08:21
quelle
1

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:

%Vor%     
Craig 29.08.2013 08:08
quelle

Tags und Links