NULL oder NOT NULL: Das ist hier die Frage!
Erscheinungsmonat |
APEX-Version |
Datenbankversion |
September 2016 |
alle |
alle |
Das Verhalten von SQL NULL (nicht nur) in der Oracle-Datenbank führt immer
wieder zu Erstaunen und zu Überraschungen ... und dabei ist das eigentlich alles
ganz einfach. Der heutige Community-Tipp beschreibt daher kurz und knapp das
Verhalten von SQL NULL und worauf man (nicht nur) als APEX-Entwickler achten sollte.
Zunächst ist NULL definiert als der "unbekannte" Wert - NULL bedeutet also
soviel wie "weiss nicht". So weit - so gut. Das Besondere ist nun, dass
Oracle bei Vergleichen mit "dreiwertiger" Logik arbeitet: das Ergebnis eines
Vergleichs kann also nicht nur wahr (true) oder falsch (false) sein, sondern auch
weiss nicht, also NULL (Tabelle 1).
Ausdruck | | Ergebnis |
{1} = {0} | | false |
{1} = {1} | | true |
{1} = {NULL} | | NULL |
{NULL} = {NULL} | | NULL |
Tabelle 1: Verhalten von SQL NULL bei Vergleichsoperationen
Die ersten beiden Zeilen sind klar; interessant ist die dritte. Der
Vergleich 1 = NULL meint übersetzt soviel wie "Ist 1 gleich dem unbekannten Wert?"
Die Antwort kann nur sein: "Weiss nicht", also NULL. Dasselbe gilt für
den Vergleich NULL = NULL; das meint soviel wie "Ist ein unbekannter Wert gleich einem anderen unbekannten Wert?" Antwort wiederum: "Weiss nicht", also NULL.
Das ist übrigens bei Negationen nicht anders (Tabelle 2).
Ausdruck | | Ergebnis |
{1} != {0} | | true |
{1} != {1} | | false |
{1} != {NULL} | | NULL |
{NULL} != {NULL} | | NULL |
Tabelle 2: Verhalten von SQL NULL bei NOT-Vergleichsoperationen.
Der Aussagewert der Unbekannten ändert sich nicht, auch
wenn man die Frage negiert. So meint 1 != NULL soviel wie
" Ist 1 ungleich der Unbekannten?". Die Antwort
lautet wiederum "Weiss nicht", könnte ja auch
gleich sein. Möchte man in Vergleichen mit NULL arbeiten, so braucht man einen
eigenen, speziellen Vergleichsoperator für SQL NULL (Tabelle 3).
Ausdruck | | Ergebnis |
{1} IS NULL | | false |
{NULL} IS NULL | | true |
{NULL} IS NOT NULL | | false |
{1} IS NOT NULL | | true |
Tabelle 3: Operatoren IS NULL und IS NOT NULL
Der erste Vergleich meint übersetzt soviel wie "Ist 1
ein unbekannter Wert?" -
das kann man klar beantworten: "1 ist bekannt", also "nein". Der Vergleich liefert
also false zurück. Die nächste Zeile fragt, ob "der unbekannte Wert unbekannt ist";
das ist wahr; als Ergebnis kommt also true heraus.
Für den Entwickler bedeutet das, dass man bei Vergleichen mit NULL immer
die dreiwertige Logik beachten muss - bei einem Vergleich mit Gleich, Ungleich,
Größer oder Kleiner kommt niemals
true, aber auch niemals false heraus. In einem IF-THEN-ELSE-Block landet man
immer im ELSE-Zweig.
Verknüpft man NULL-Werte mit bool'schen Operatoren wie AND oder OR, so verhält sich
SQL NULL ebenfalls etwas anders als bekannte Werte. Tabelle 4 enthält Details.
Ausdruck | | Ergebnis |
{true} and {NULL} | | NULL |
{false} and {NULL} | | false |
{true} or {NULL} | | true |
{false} or {NULL} | | NULL |
Tabelle 4: AND, OR und SQL NULL
- Fangen wir mit der ersten AND-Verknüpfung an: Die linke Seite ist mit true bekannt,
die rechte Seite ist unbekannt (NULL). Das Ergebnis hängt also von der rechten
Seite ab: Wenn die rechte Seite true wäre, wäre das Ergebnis ebenfalls true, wenn sie
false wäre, dann ergäbe sich als Ergebnis false. Beides ist also möglich; also ergibt sich
NULL als Ergebnis.
- Bei der zweiten AND-Verküpfung ist die linke Seite mit false bekannt, die
rechte Seite ist unbekannt (NULL). Nun ist es egal, wie die rechte Seite
aussieht; wenn bei einer AND-Verknüpfung eine Seite false ist, kommt immer
false heraus. Die Datenbank kann also mit Sicherheit sagen, dass false herauskommt.
- Die OR-Verknüpfungen lassen sich ähnlich erklären. OR reagiert mit true genauso
wie AND mit false. Hat eine Seite den Wert true, kommt immer true heraus.
Die Datenbank kann also mit Sicherheit sagen, dass true herauskommt.
- Die letzte OR-Verknüpfung mit false erklärt sich wie die erste AND-Verküpfung. Das
Ergebnis hängt von der rechten Seite ab; die Datenbank weiss es also
nicht; das Ergebnis ist NULL.
Daneben gibt es in der Oracle-Datenbank (wie immer) noch einige Besonderheiten ...
- Der Leerstring in einem VARCHAR2 ist in Oracle als SQL NULL definiert. In Oracle kann
man den Leerstring also nicht mit WHERE NAME = '' abfragen - nur mit WHERE NAME IS NULL. Das gilt jedoch nicht bei einem CLOB - dort gibt es sehr wohl einen Unterschied zwischen SQL NULL und einem leeren CLOB mit der Länge "0".
- Bei Aggregatsfunktionen wird SQL NULL normalerweise ignoriert - nach dem bis hierher gelesenen müsste das Ergebnis einer Aggregatsfunktion wie SUM oder AVG stets SQL NULL sein, sobald sich auch nur ein NULL-Wert in den aggregierten Zeilen befindet. Das ist nicht der Fall - Oracle ignoriert die NULLs hier einfach - was ist der Praxis ja auch nützlicher ist.
- Wenn es um das Gruppieren geht, wird NULL wie ein eigener, bekannter Wert behandelt - es wird
also eine Gruppe für alle SQL NULLs gebildet. Das ist zwar strenggenommen nicht ganz richtig; man müsste eigentlich für jedes SQL NULL eine eigene Gruppe bilden - sowas wäre in der Praxis jedoch völlig
unbrauchbar - so wie die Datenbank das macht, dürfte also die einzig sinnvolle Variante sein.
Der Umgang mit SQL NULL ist also einfacher als man denkt - solange man die "dreiwertige" Logik
im Auge behält, die true, false oder NULL zurückgeben kann.
Zurück zur Community-Seite
|