ORA-01858: Ein nicht-numerisches Zeichen wurde gefunden….

Heute bewege ich mich in der Programmiersprache PLSQL auf Oracle.

Der Fehler den ich heute hatte ist ganz detailliert dieser :

ORA-01858: Ein nicht numerisches Zeichen wurde gefunden, während ein numerisches Zeichen erwartet wurde

bzw:

ORA-01858: a non-numeric character found where a digit was expected

Der Code dazu war im wesentlichen, ein For-Loop über ein Select-Statement, dass selbst wiederum eine View selektiert. Hier der Code, stark vereinfach und auf das Wesentliche reduziert:

for c1 in (
      select id,
             gebdatum
             nachname,
             vorname,
             anschrift
      from personen_view1
      where datum = sysdate ....
)
loop

      if ( c1.nachname = 'Müller' ) then
          --eigentliche logik ...
      end if;
      ......
end loop;

Die Backtrace Information der Exception hat den Fehler dabei in der ersten zeile  (also for c1…) ausgemacht. Der Fehler trat nicht sofort auf, sondern erst nach ein paar Minuten nach Start der Prozedur.

Grundsätzlich bedeutet die Fehlermeldung ja, dass die Datenbank eine Zahl erwartet hat, aber Buchstaben gefunden hat. Klassischer Konvertierungsfehler so mein erster Gedanke.

Mein erster Ansatz war also die View und deren Definition zu untersuchen : Sind alle Datentypen richtig erkannt ? Ist mir in der Prozedur ein Fehler unterlaufen, sodass ich mit einem Char-Feld rechne ? Rechne ich mit Datümern ? Sind in der View alle Konvertierungen sauber ? Wird mit Null-Werten richtig umgegangen?
Die View war diesbezüglich in Ordnung. Ein einfaches Select-Statement lief sauber durch und lieferte keine Indizien.

Also musste der Fehler in der Prozedur selbst liegen. Also habe ich sukzessive den ganzen Code auskommentiert und bin bei eben obiger Vereinfachung geblieben. Der Fehler war also eingegrent und konnte schnell und einfach nachgestellt werden.

Mit folgender Abänderung lief die Prozedur fehlerfrei aber mit falschen Ergebnissen durch:

for c1 in (
      select id,
             gebdatum
             nachname,
             vorname,
             anschrift
      from personen_view1
      where datum = sysdate ....
)
loop
      -- To Char Konvertierung um Fehler einzugrenzen
      if (to_char(c1.nachname) = 'Müller' ) then
          --eigentliche logik ...
      end if;
      ......
end loop;

Die fehlerhafte Typkonvertierung musste also nach der View, aber vor diesem ersten If passieren. Ein weiteres Indiz um der Ursache näher zu kommen war den Select ohne explizite Spaltenauflistung, sondern nur mit „*“ auszuführen. Auch hier lief die Prozedur fehlerfrei.

Des Rätsels Lösung befindet sich in der Zeile mit der Spaltenauflistung für Gebdatum. Es fehlt hier ein Komma (Ende Zeile 03). Dadurch wird die darauffolgende Spalte „Name“ nicht zur Spaltenauflistung der Selects, sondern nur  zum Alias der Spalte „Gebdatum“. Der Vergleich auf den Nachnamen Müller vergleicht nun also nicht „Müller“ mit der Spalte „nachname“ der View sondern mit dem „gebdatum“, dass durch nur anders heisst. Insgesamt also ein dummer Copy & Paste Fehler der im größeren Aufbau nur schwer zu finden war.

Aber warum trat der Fehler erst nach ein paar Minuten auf ? Dieser Fehler hätte sofort und beim ersten Datensatz auffallen müssen. Mit Blick auf den Explain Plan des SQL-Statements bzw. der View wird klar, dass das Ergebnis über einen Hash-Join gebildet wird. Diese Form des Joins hat die Auswirkung, dass der erste Aufbau des Cursors relativ lange dauert (besagte Minuten) , beim Iterieren über die Datensätze aber dafür schneller Daten liefern als mit Nested-Loops. Der Fehler ist also wirklich auch schon beim ersten Fehler aufgetaucht, weil es eben Minuten dauerte um den ersten Satz zu liefern.

Dieser Beitrag wurde unter Datenbanken veröffentlicht. Setze ein Lesezeichen auf den Permalink.