2009-03-02 3 views
7

Ich habe eine Abfrage, dieOracle10 und JDBC: wie CHAR nachfolgende Leerzeichen beim Vergleich ignorieren?

hat ... WHERE PRT_STATUS = 'ONT' ...

Das prt_status Feld als CHAR (5), obwohl definiert ist. Es wird also immer mit Leerzeichen aufgefüllt. Die Abfrage stimmt mit nichts überein. Um diese Abfrage Arbeit zu machen habe ich

... WHERE rtrim (PRT_STATUS) = 'ONT'

die Arbeit erledigt zu tun.

Das ist ärgerlich.

Zur gleichen Zeit, ein paar pure-Java-DBMS-Clients (Oracle SQLDeveloper und AquaStudio) Ich habe kein Problem mit der ersten Abfrage, sie geben das richtige Ergebnis zurück. TOAD hat auch kein Problem.

Ich nehme an, dass sie die Verbindung einfach in einen Kompatibilitätsmodus (z. B. ANSI) versetzen, so dass das Oracle weiß, dass CHAR (5) ohne Rücksicht auf nachfolgende Zeichen erwartet wird.

Wie kann ich es mit Connection-Objekten, die ich in meiner Anwendung bekomme?

UPDATE Ich kann das Datenbankschema nicht ändern.

LÖSUNG Es war in der Tat die Art, wie Oracle Felder mit übergebenen Parametern vergleicht.

Wenn die Bindung abgeschlossen ist, wird die Zeichenfolge über PreparedStatement.setString() übergeben, wodurch der Typ auf VARCHAR festgelegt wird. Daher verwendet Oracle ungepolten Vergleich - und schlägt fehl.

Ich habe versucht, SetObject (n, str, Types.CHAR) zu verwenden. Schlägt fehl. Dekompilierung zeigt, dass Oracle CHAR ignoriert und es als VARCHAR erneut übergibt.

Die Variante, die schließlich funktioniert, ist

setObject(n,str,OracleTypes.FIXED_CHAR); 

Es macht den Code aber nicht tragbar.

Die UI-Clients sind aus einem anderen Grund erfolgreich - sie verwenden Zeichenliterale, die nicht bindend sind. Wenn ich PRT_STATUS = 'ONT' eintippe, ist 'ONT' ein Literal und wird daher mit einem gepolsterten Weg verglichen.

Antwort

8

Beachten Sie, dass Oracle compares CHAR values using blank-padded comparison semantics.

Von Datatype Comparison Rules,

Oracle Semantik nur mit Leerzeichen aufgefüllt Vergleich verwendet, wenn beide Werte im Vergleich entweder Ausdrücke von Datentyp CHAR sind, NCHAR, Textliterale, oder Werte, die von der USER Funktion zurückgegeben werden.

In Ihrem Beispiel wird 'ONT' als Bind-Parameter übergeben, oder wird es in die Abfrage textlich gebaut, wie Sie dargestellt? Wenn ein bind-Parameter, dann stellen Sie sicher, dass es als Typ CHAR gebunden ist. Andernfalls überprüfen Sie die verwendete Client-Bibliotheksversion, da wirklich alte Versionen von Oracle (z. B. v6) eine andere Vergleichssemantik für CHAR haben.

+0

Das ist in Ordnung. Siehe meine aktualisierte Antwort dann. – vladr

+0

Hmm ... das macht Sinn. JDBCs setString verwendet VARCHAR, um einen Zeichenfolgenparameter zu binden. Ich bin mir nicht sicher, ob ich damit das Problem lösen kann, aber zumindest wird es jetzt klarer. –

+0

Sie haben wahrscheinlich Recht: "Oracle verwendet nicht gepackte Vergleichssemantik, wenn einer oder beide Werte im Vergleich den Datentyp VARCHAR2 oder NVARCHAR2 haben". Ich muss einen Test machen, um es zu überprüfen. –

0

Ich würde CHAR (5) Spalte in varchar2 (5) in db ändern.

+0

außer Frage verwenden. DB gehört nicht zu unserer Gruppe. –

1

Wenn Sie Ihre Datenbanktabelle nicht ändern können, können Sie Ihre Abfrage ändern.

Einige Alternativen für RTRIM:

.. WHERE PRT_STATUS wie 'ONT%' ...

.. WHERE PRT_STATUS = 'ONT' ... - 2 weißen Räume hinter T

.. WHERE PRT_STATUS = rpad ('ONT', 5‘‚) ...

0

Sie cast char Operation in Ihrer Abfrage verwenden können:

... WHERE PRT_STATUS=cast('ONT' as char(5)) 

oder in allgemeinerer JDBC Weise:

... WHERE PRT_STATUS=cast(? as char(5)) 

Und dann in Ihrem JDBC-Code do statement.setString(1, "ONT");

Verwandte Themen