Es scheint so, dass alle gängigen Oracle-Datenbanken leere Zeichenketten und null nicht unterscheiden. Das widerspricht der SQL-Spezifikation und ist damit ein Fehler.
Leider wäre es für Oracle nicht einmal einfach, den zu entfernen, weil zu viele Applikationen seit Jahrzehnten Oracle benutzen und sich auf dieses Verhalten eingestellt haben.
Entscheidend ist also erst einmal, diesen Fehler zu kennen und bei der Verwendung von Oracle-Datenbanken zu berücksichtigen. Solange man explizit mit SQL, also SQL*Plus, JDBC, DBI, Pro*C u.ä. auf die Datenbank zugreift, ist es noch einfacher, das zu berücksichtigen, aber heikel wird es bei der Verwendung von Frameworks wie Hibernate, wo man merkwürdige Fehler findet. Wenn man zum Beispiel eine Entität (engl. Entity) hat, die persistiert wird, und dort ein Attribut eine Zeichenkette ist, kann man legitimerweise dort die leere Zeichenkette zuweisen. Sobald dieses Objekt durch Hibernate wandert und persistiert wird, hat man plötzlich stattdessen null dort stehen und bekommt unerwartete NullPointerExceptions. Oder das Attribut ist in der Datenbank mit dem NOT-NULL-Constraint versehen und man bekommt beim Schreiben Oracle-Fehler. Außerdem ist es natürlich ein semantisches Problem, man möchte vielleicht gerne leere Zeichenketten und null dort speichern können und mit verschiedenen Bedeutungen behandeln.
Eine hässliche, aber doch praktikable Möglichkeit, damit umzugehen ist die Getter und Setter der Zeichenketten-Attribute entsprechend zu ändern. Man kann eine „magische Zeichenkette“ definieren, die man garantiert nicht als Wert dort speichern möchte. Dann kann man im Getter vergleichen, ob das Attribut diese Zeichenkette als Wert hat und in dem Fall die leere Zeichenkette zurückgeben. Und im Setter prüft man erst, ob der neue Wert diese magische Zeichenkette ist, was man mit einer Exception ablehnt, und andernfalls, ob der neue Wert die leere Zeichenkette ist, was man durch die magische Zeichenkette ersetzt.
Bespiel in Java (ohne JPA-Annotationen, Synchronisation, toString(), hashCode(), equals() u.s.w.; geht analog für andere Programmiersprachen)
public class MyEntity {
private static String MAGIC_VALUE = "_._._«NULL»_._._";
private String value;
public String getValue() {
if (MAGIC_VALUE.equals(value)) {
return "";
} else {
return value;
}
}
public void setValue(String newValue) {
if (MAGIC_VALUE.equals(newValue)) {
throw new IllegalArgumentException("value="+newValue+" not allowed");
} else if ("".equals(newValue)) {
this.value = MAGIC_VALUE;
} else {
this.value = newValue;
}
}
}
Damit das ganze auch mit Attributen funktioniert, die in der Datenbank als VARCHAR(1) oder VARCHAR(2) definiert sind, ist es vielleicht eine gute Idee, Steuerzeichen oder UTF-8-Zeichen aus einer Sprache, die man nie unterstützen will, zu verwenden. Aber es bleibt eine unbefriedigende Lösung.
Hat jemand eine bessere Idee dazu?
Gibt es noch andere Datenbanken, die den gleichen Fehler wie Oracle in diesem Punkt haben?
mir hat einmal einer gesagt, wenn du ein NULL-Feld in einer Datenbank definierst, solltest du darueber nachdenken, ob du das Feld ueberhaupt brauchst, also alle Felder immer NOT NULL und das Problem (und viele andere) treten nie auf. Das habe ich seit dem beherzigt und wahrscheinlich damit einige Tage Lebenszeit gewonnen.
Danke für diesen Kommentar, das ist ein guter Punkt und man erleichtert sich das Leben sehr, wenn man das NOT NULL so oft wie sinnvoll möglich verwendet.
Tückisch ist aber bei Oracle, dass man damit auch leere Zeichenketten verbietet, die bei vielen anderen Datenbanksystemen trotz NOT NULL erlaubt sind.