NULL in SQL: Platzhalter für fehlende Daten


„Jeder [SQL] Datentyp beinhaltet einen speziellen Wert, genannt der Null-Wert,“0 „der genutzt wird, um das Fehlen eines Datenwertes anzuzeigen“.1

Der Null-Wert zeigt nicht an, warum ein Wert fehlt – er markiert bloß Stellen, für die es keinen Wert gibt. SQL selbst verwendet den Null-Wert unter anderem im Ergebnis eines outer joins.2 Obwohl es Ausnahmen gibt,3 kann man im Allgemeinen nicht sagen, warum ein Wert Null ist.

Benutzer können den Null-Wert für beliebige Zwecke einsetzen. Die vermutlich häufigste Anwendung ist, optionale Attribute ohne zusätzlicher Tabelle umzusetzen. Die Fehlerbehandlung ist ein anderer, wichtiger Anwendungsfall: anders als bei anderen Programmiersprachen verursacht die Verarbeitung von Null-Werten in SQL keinen Fehler oder Abbruch – Null-Werte propagieren einfach durch Ausdrücke hindurch.

Inhalt:

  1. Vergleiche mit Null
  2. Null in nicht-Null Werte wandeln und umgekehrt
  3. Null breitet sich durch Ausdrücke aus
  4. Null in Aggregatfunktionen (count, sum, …)
  5. Null in Distinct, Group by, Partition by, Union, …
  6. Null in Order By
  7. Null in Unique Constraints
  8. Kompatibilität

Vergleiche mit Null

Vergleiche (<, >, =, …) mit Null liefern weder true (wahr) noch false (falsch) sondern den dritten logischen Wert von SQL: unknown (unbekannt). Da die Where-Klausel unknown wie false behandelt, entfernt sie im folgenden Beispiel alle Zeilen – selbst jene, bei denen col tatsächlich Null ist.

WHERE col = null

Warnung

Die SQL Server-Einstellung SET ANSI_NULLS OFF ändert dieses Verhalten.

Auf Null testen: is [not] null

Das SQL-Prädikat is [not] null testet, ob der Wert eines Ausdruckes Null oder nicht Null ist.

<Ausdruck> is null

Dieses Beispiel liefert true, wenn der Wert des Ausdruckes Null ist oder false, wenn nicht. Das optionale not negiert das Ergebnis.

Null-sicherer Vergleich: is not distinct from

SQL kennt zwei unterschiedliche Kriterien, um zu bestimmen ob zwei Werte „gleich“ sind: Gleichheit (=) und Unterscheidbarkeit (distinct). Der Unterschied ist, dass das beim Gleichheitszeichen (=) vergleiche mit Null unentscheidbar sind – daher liefert col = null als Ergebnis unknown. Bei einem Test auf Unterscheidbarkeit werden Null-Werte aber wie normale Werte behandelt. Daher sind zwei Null-Werte ununterscheidbar („gleich“), während ein nicht-Null-Wert von einem Null-wert sehr wohl unterscheidbar ist.

Ursprünglich wurde das Unterscheidbarkeitskriterium im SQL-Standard nur intern genutzt, um das Verhalten von group by, select distinct, count(distinct …) und dergleichen zu definieren. SQL:1999 und SQL:2003 haben dann das is [not] distinct from-Prädikat eingeführt, damit der Test auf Unterscheidbarkeit auch von SQL-Programmieren genutzt werden kann.

<Ausdruck1> IS NOT DISTINCT FROM <Ausdruck2>

Das is [not] distinct from-Prädikat ist ein optionales Feature, das nicht von allen Datenbanken unterstützt wird. Siehe NULL-sichere Vergleiche: is [not] distinct from für Alternativen.

Null in nicht-Null Werte wandeln und umgekehrt

Manchmal ist es nötig, einen speziellen Wert durch den Null-Wert zu ersetzen oder umgekehrt, Null durch einen anderen Wert zu ersetzen. Der Case-Ausdruck bietet dafür sogar zwei Kurzformen an.

CoalesceNull durch einen anderen Wert ersetzen

SQL’s coalesce ersetzt Null durch einen anderen Wert.

COALESCE(<Ausdruck>, 0)

Das Beispiel liefert den Wert des Ausdrucks, außer es ist der Null-Wert. Dann ist das Ergebnis die Zahl 0.

Coalesce akzeptiert beliebig viele Argumente und liefert den ersten nicht-Null-Wert oder Null, wenn alle Argumente Null sind.

Nullif — Einen einzelnen Wert durch Null ersetzen

SQL’s Nullif ersetzt einen einzelnen Wert durch Null. Wenn die beiden Argumente gleich sind (=), ist das Ergebnis von Nullif Null. Andernfalls wird das erste Argument als Ergebnis geliefert.

NULLIF(<Ausdruck>, <Ausdruck>)

Case — Mehrere Werte durch Null ersetzen

Mit dem allgemeinen Case-Ausdruck kann man natürlich andere Fälle abdecken – z. B. mehrere Werte in einem Schritt durch Null ersetzen:

CASE WHEN <Ausdruck> IN (…)
     THEN null
     ELSE <Ausdruck>
 END

Natürlich kann man im Case-Ausdruck auch andere Vergleiche durchführen: >, <, between und so weiter.

Null breitet sich durch Ausdrücke aus

Ausdrücke und Funktionen, die einen Null-Wert verarbeiten, liefern grundsätzlich Null als Ergebnis.4 Nennenswerte Ausnahmen sind Aggegatfunktionen und – aufgrund der dreiwertigen Logik von SQL – zwei logische Operationen.5

Das Ergebnis der folgenden Ausdrücke ist daher immer Null:

1 + NULL
'foo ' || NULL || 'bar'
SUBSTRING('foo bar' FROM 4 FOR NULL)

Abweichungen: Oracle und SQL Server Datenbanken

Die Oracle-Datenbank behandelt den Leerstring wie Null und umgekehrt. Einerseits ist '' IS NULL true, andererseits wird Null beim Zusammenfügen von Zeichenketten (||) wie ein Leerstring behandelt. Das Ergebnis des zweiten Beispiels ist bei der Oracle-Datenbank daher 'foo bar'.

SQL Server bietet die überholte (deprecated) Einstellung SET CONCAT_NULL_YIELDS_NULL OFF an, um Null beim Zusammenfügen von Zeichenketten mittels + wie einen Leerstring zu behandeln. Beachte: die Funktion concat behandelt Null immer als Leerstring.

Hinweis: Proprietäre Funktionen

Die meisten Datenbanken unterstützten mehr Funktionen als vom SQL-Standard definiert. Diese Funktionen müssen nicht unbedingt der Idee folgen, dass sich Null ausbreitet.

Die Funktion concat() zum zusammenfügen von Strings ist ein wichtiges Beispiel, weil sie von sehr vielen Datenbanken angeboten wird. Die Behandlung von Null in den Eingangsdaten ist jedoch unterschiedlich: Db2, MySQL und MariaDB handeln im Sinne des SQL-Standard und liefern Null als Ergebnis. H2, Oracle, PostgreSQL und SQL Server behandeln Null in concat() wie einen Leerstring.

In logischen Ausdrücken (and, or, not) ist Null gleichbedeutend mit unknown.6 Null (unknown) pflanzt sich nur durch logische Ausdrücke fort, wenn das Ergebnis durch einen Null-Wert unentscheidbar wird. Daher gibt es zwei Fälle, bei denen das Ergebnis trotz eines Null-Operanden nicht Null ist: Null and false ist false, weil die logische Konjunktion (and) false ist, sobald ein Argument false ist. Analog liefert null or true das Ergebnis true.

Null in Aggregatfunktionen (count, sum, …)

Grundsätzlich entfernen Aggregatfunktionen Null-Werte aus der Eingangsmenge bevor sie die Aggregierung durchführen.7 Das bedeutet, dass das Ergebnis einer Aggregatfunktion durch einen Null-Wert nicht automatisch Null wird. Dieses Verhalten wird oft zur Umsetzung von Pivot-Abfragen genutzt.

Denksport

Wie wirkt sich die Ausbreitung des Null-Wertes durch Ausdrücke und das Entfernen von Null-Werten vor der Aggregation auf die folgenden Ausdrücke aus:

SUM(a+b)
SUM(a) + SUM(b)

Das Ergebnis einer Aggregatfunktion ist nur Null, wenn eine effektiv leere Eingangsmenge vorliegt. Das ist der Fall, wenn (1) alle Zeilen vor der Aggregierung entfernt werden (z. B. aufgrund einer Filter-Klausel oder weil es Null-Werte sind), oder (2) ein explizites oder implizites group by () auf einer tatsächlich leeren Menge durchgeführt wird.8

Count und regr_count liefern niemals Null. Bei einer effektiv leeren Eingangsmenge liefern diese Funktionen den numerischen Wert 0.9

Hinweis in eigener Sache

Ich biete SQL Schulungen, Optimierung und Beratung an. Auch der Kauf meines Buches „SQL Performance Explained“ (ab €9,95) unterstützt meine Arbeit an dieser Webseite.

Aggregatfunktionen, die strukturierte Daten liefern (array_agg, json_objectagg, xmlagg), entfernen Null-Werte nicht.10 Im Gegensatz zu json_objectagg verwendet json_arrayagg die Standardeinstellung absent on null und entfernt daher Null-Werte.11 Die meisten Produkte verwenden null on null als Standardeinstellung für json_arrayagg.

Null in Distinct, Group by, Partition by, Union, …

Gruppierungen werden aufgrund des Unterscheidbarkeitskriteriums is not distinct from durchgeführt.12 Daher werden alle Null-Werte in eine Gruppe zusammengefasst.

Das betrifft auch andere Operationen, die auf Basis einer Gruppierung definiert sind: distinct (in select und Aggregatfunktionen), partition by, union (ohne all), ….13

Null in Order By

Der SQL Standard überlässt die Sortierung von Null-Werte relativ zu nicht-Null-Werten den Herstellern:14 Null-Werte können entweder vor, oder nach den nicht-Null-Werten einsortiert werden (siehe Kompatibilität).

SQL:2003 hat den order by-Zusatz nulls (first|last) eingeführt, damit SQL-Entwickler die Sortierung von Null-Werten steuern können. Dieser Zusatz wird derzeit nur von wenigen Datenbanken unterstützt (siehe Kompatibilität).

ORDER BY <expression> [ASC|DESC] [NULLS (FIRST|LAST)]
     [ , <expression> [ASC|DESC] [NULLS (FIRST|LAST)] ]
       …

Der Effekt von nulls (first|last) kann mit einem Case-Ausdruck jedoch in allen Datenbanken erreicht werden. Das folgende Beispiel setzt order by c nulls first auf diese Weise um:

ORDER BY CASE WHEN c IS NULL
              THEN 0
              ELSE 1
          END
       , c

Beachte, dass der Case-Ausdruck einen neuen Sortierschlüssel definiert, der nur dazu dient, die Null- von den nicht-Null-Werten zu trennen.

Null in Unique Constraints

In Unique-Constraints ist der Null-Wert ungleich allem – d. h. ungleich Null und ungleich anderen Werten.15 Da dadurch jede Null eine andere Null ist, akzeptieren Unique-Constraints mehrere Null-Werte.

Zukunftsmusik: NULLS [NOT] DISTINCT

Ein Entwurf zum nächsten SQL-Standard führt den Nulls [not] distinct-Zusatz ein um den Umgang von Null-Werten in Unique-Constraints steuern zu können. Entgegen SQL:2016 ist das Default-Verhalten dann von der Implementierung definiert. Weiters ist es auch bei nulls not distinct erlaubt, mehrere Null-Werte im Unqiue-Constraint zu akzeptieren, wenn alle Spalten des Constratins den Null-Wert beinhalten.

BigQueryaaDb2 (LUW)aaMariaDBMySQLOracle DBbcPostgreSQLSQL ServerSQLitedefault: nulls distinctdefault: nulls not distinct
  1. Unterstützt keine Null-baren Spalten in Unique-Constraints (T591)
  2. Wenn alle Spalten des Constraints Null sind
  3. Wenn manche, aber nicht alle Spalten des Constraints Null sind

Kompatibilität

Null ist von Anfang an Teil des SQL-Standards. Unique-Constraints auf Spalten mit Null-Werten wurde von intermediate SQL-92 gefordert. Seit SQL:1999 ist das ein optionales Feature (T591).

Die explizite Sortierung von Null-Werten (nulls (first|last)) wurde mit SQL:2003 als Teil des optionalen Features T611, “Elementary OLAP operations”, eingeführt.

BigQuerycgDb2 (LUW)dhMariaDBgMySQLgOracle DBaehPostgreSQLbhSQL ServerbfgSQLitegNullUNIQUE erlaubt mehrere Null-Werteorder by … nulls (first|last)is distinct fromis not distinct from
  1. Leerstring is null. Beim Zusammenfügen wirkt Null wie ein Leerstring • concat() behandelt Null wie einen Leerstring
  2. concat() behandelt Null wie einen Leerstring
  3. Unterstützt keine Unique-Constrains
  4. Unterstützt keine Unique-Constrains auf Spalten ohne not null-Constraint
  5. Abweichend bei mehrspaltigen Constraints (siehe Oben)
  6. Erlaubt nur einen Null-Wert
  7. Voreinstellung: Sortierung als kleinster Wert
  8. Voreinstellung: Sortierung als größter Wert

20 Jahre SQL-Evolution kann man nicht an einem Tag nachholen. Abonniere den Newsletter via E-Mail, Twitter oder RSS um sukzessive aufzuholen und modern-sql.com am Radar zu behalten.

Über den Autor

Foto von Markus Winand

Markus Winand gibt auf modern-sql.com Einblick in SQL und zeigt, wie es von verschiedenen Systemen unterstützt wird. Zuvor machte er use-the-index-luke.com, was er noch immer wartet. Markus kann als Trainer, Sprecher und Berater auf winand.at engagiert werden.

Sein Buch kaufen

Titelbild von „SQL Performance Explained“: Eichhörnchen läuft durchs Grass

Die Essenz: SQL-Tuning auf 200 Seiten

Jetzt Kaufen
(Taschenbuch und/oder PDF)

Sein Training

Markus verwandelt veraltetes SQL-92-Wissen in solides und zeitgemäßes SQL-Know-how

Erfahren Sie mehr»

Fußnoten

  1. SQL:2011-1: §4.4.2

  2. SQL:2011-1: §3.1.1.12

  3. SQL:2016-2: §7.10 General Rule 3c und 4

  4. Bei grouping sets, kann man mit der Grouping-Funktion unterscheiden, ob ein Null-Wert aus den Daten kommt, oder aufgrund der Gruppierung zustande gekommen ist.

  5. Für numeric value Ausdrücke: SQL:2016-2: §6.29 General Rule 1

    Für string value Ausdrücke: SQL:2016-2: §6.31 General Rule 1

    Für datetime value Ausdrücke: SQL:2016-2: §6.35 General Rule 1

    Für interval value Ausdrücke: SQL:2016-2: §6.38 General Rule 2

  6. TRUE OR NULL ist zum Beispiel TRUE.

  7. SQL:2016-2: §4.5.1

  8. SQL:2016-2: §4.16.4

  9. Beispiel: select min(c) from empty_table

    SQL:2016-2: §7.16 Syntax Rule 16 (implizites GROUP BY ()), SQL:2016-2: §7.13 General Rule 2a.

  10. SQL:2016-2: §10.9 General Rule 5 (count) und 8c (regr_count). Diese Ausnahme (0, nicht Null) hat in frühen Datenbanken Fehler verursacht („The COUNT bug“; Kiessling, W. 1984).

  11. Für array_agg wird das in SQL:2016-2: §10.9, General Rule 12gii, note 510 explizit erwähnt.

  12. SQL:2016-2: §10.11 SR 5a

  13. SQL:2016-2: §4.1.5

  14. Siehe SQL:2016-2: §9.12 für eine vollständige Liste.

    Eigentlich sind die Set-Funktionen auf Basis des Begriffes „Duplikat“ definiert (SQL:2016-2: §7.17 General Rule 3biii). Dieser Begriff ist jedoch durch das Unterscheidbarkeitskriterium definiert (SQL:2016-2: §3.1.6.11).

  15. SQL:2016-2: §10.10 Syntax Rule 3

  16. Eigentlich sind Unique-Constraints auf Basis des unique-Prädikates definiert (SQL:2016-2: §11.7 Syntax Rule 6), welches wiederum auf Basis der Unterscheidbarkeit definiert ist, wenn ein nicht-Null-Wert beteiligt ist (SQL:2016-2: §8.11 General Rule 2).

  17. Die Oracle-Datenbank ist im Umgang mit Null in Unique-Constraints nicht Standardkonform: die Oracle erfüllt die Anforderung auch ohne weiteres zutun.

  18. MySQL und MariaDB bieten aber auch physisch gespeicherte generated columns an.

Mit Markus Winand verbinden

Markus Winand auf LinkedInMarkus Winand auf XINGMarkus Winand auf Twitter
„modern SQL“ von Markus Winand ist unter einer Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License lizenziert.
Impressum | Kontakt | KEINE GEWÄHR | Handelsmarken | Datenschutz und DSGVO | CC-BY-NC-ND 3.0 Lizenz