im Datenbankvergleich sauber verstanden
Wo ein NULL-Wert in einer sortierten Ergebnismenge landet und mit welcher Funktion man ihn durch einen Ersatzwert ersetzt, klingt nach einer Randnotiz, ist aber zwischen MySQL, PostgreSQL, SQL Server und Oracle grundverschieden geregelt. Wer Sortierlogik und NULL-Handling zwischen diesen Systemen portabel halten will, muss NULLS FIRST, NULLS LAST, COALESCE, IFNULL, ISNULL und NVL im Detail auseinanderhalten koennen.
Inhaltsverzeichnis
- 1. Warum NULL bei Sortierung und Ersatzwerten besonders behandelt werden muss
- 2. Standardverhalten: NULLS FIRST vs. NULLS LAST je Datenbank
- 3. Explizite Steuerung mit NULLS FIRST/LAST wo unterstuetzt
- 4. Workarounds fuer Datenbanken ohne native NULLS FIRST/LAST Syntax
- 5. COALESCE als ANSI Standard und seine Kurzschluss-Auswertung
- 6. Proprietaere Alternativen: IFNULL, ISNULL, NVL im Vergleich
- 7. NULL in Vergleichsoperatoren und die Drei-Wertige-Logik kurz eingeordnet
- 8. Portable Patterns fuer NULL-Handling in Anwendungscode
- 9. NULL-Handling-Funktionen im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum NULL bei Sortierung und Ersatzwerten besonders behandelt werden muss
Ein NULL-Wert repraesentiert das Fehlen eines Werts, nicht eine leere Zeichenkette oder eine Null als Zahl, und genau diese Sonderrolle macht ihn in zwei alltaeglichen SQL-Aufgaben besonders tricky: bei der Sortierung mit ORDER BY und beim Ersetzen fehlender Werte durch einen sinnvollen Standardwert. Da NULL keinen definierten Vergleichswert hat, muss jede Datenbank eine eigene Konvention festlegen, ob NULL-Zeilen am Anfang oder Ende einer sortierten Ergebnismenge erscheinen, und diese Konvention unterscheidet sich zwischen MySQL, PostgreSQL, SQL Server und Oracle spuerbar.
Aehnlich fragmentiert ist die Landschaft bei Funktionen, die einen NULL-Wert durch einen Ersatzwert ersetzen. Der ANSI-Standard definiert dafuer COALESCE(), doch mehrere Datenbanken bieten zusaetzlich proprietaere Kurzformen wie IFNULL(), ISNULL() oder NVL(), die sich in Argumentanzahl, Typkonvertierung und Kurzschluss-Verhalten unterscheiden. Wer Anwendungen fuer mehrere Datenbanken schreibt, muss beide Themenbereiche, Sortierung und Ersatzwerte, sauber auseinanderhalten, da sie oft gemeinsam in derselben Abfrage auftreten, etwa bei einer nach Datum sortierten Liste, in der fehlende Daten sowohl korrekt einsortiert als auch sinnvoll angezeigt werden muessen.
2. Standardverhalten: NULLS FIRST vs. NULLS LAST je Datenbank
Der ANSI-SQL-Standard selbst schreibt kein festes Standardverhalten fuer die Position von NULL-Werten in einer sortierten Ergebnismenge vor und ueberlaesst diese Entscheidung explizit den Herstellern. PostgreSQL und Oracle haben sich dafuer entschieden, NULL-Werte bei aufsteigender Sortierung (ASC) standardmaessig ans Ende zu stellen, so als waeren sie groesser als jeder andere Wert, waehrend sie bei absteigender Sortierung (DESC) folgerichtig an den Anfang wandern.
MySQL und SQL Server haben die entgegengesetzte Konvention gewaehlt: NULL-Werte gelten hier als kleinster moeglicher Wert und erscheinen bei ASC-Sortierung standardmaessig am Anfang, bei DESC-Sortierung am Ende. Dieser Unterschied ist einer der am haeufigsten uebersehenen Stolpersteine bei einer Migration zwischen den beiden Datenbank-Familien, da eine funktionierende, ungetestete Abfrage nach der Migration ploetzlich Zeilen mit fehlenden Werten an einer voellig anderen Position in der Ergebnisliste anzeigt.
-- PostgreSQL and Oracle: NULL sorts as if it were larger than any value
-- With ASC, NULL rows appear LAST by default
SELECT id, discount_percent FROM products ORDER BY discount_percent ASC;
-- Example order: 5, 10, 15, NULL, NULL
-- MySQL and SQL Server: NULL sorts as if it were smaller than any value
-- With ASC, NULL rows appear FIRST by default
SELECT id, discount_percent FROM products ORDER BY discount_percent ASC;
-- Example order: NULL, NULL, 5, 10, 15
3. Explizite Steuerung mit NULLS FIRST/LAST wo unterstuetzt
PostgreSQL und Oracle bieten mit den optionalen Schluesselwoertern NULLS FIRST und NULLS LAST direkt am Ende einer ORDER BY-Spalte eine explizite, vom impliziten Standardverhalten unabhaengige Steuerung. Diese Syntax ist Teil des ANSI-Standards und erlaubt es, unabhaengig von der Sortierrichtung genau festzulegen, ob NULL-Werte zuerst oder zuletzt erscheinen sollen, was insbesondere bei Reports mit gemischter Sortierrichtung fuer Konsistenz sorgt.
MySQL und SQL Server unterstuetzen diese Syntax bis heute nicht nativ, was bedeutet, dass Entwickler auf beiden Systemen auf Workarounds zurueckgreifen muessen, sobald das gewuenschte Verhalten vom jeweiligen Standardverhalten abweicht. Dieser fehlende Support ist einer der konkretesten Faelle, in denen die vier grossen Datenbanken bei einer eigentlich vom Standard abgedeckten Aufgabe syntaktisch komplett auseinanderlaufen.
-- PostgreSQL and Oracle: explicit NULLS FIRST / NULLS LAST
SELECT id, discount_percent
FROM products
ORDER BY discount_percent ASC NULLS FIRST;
-- Forces NULL rows to appear first, overriding the ASC default of NULLS LAST
SELECT id, discount_percent
FROM products
ORDER BY discount_percent DESC NULLS LAST;
-- Forces NULL rows to appear last, overriding the DESC default of NULLS FIRST
4. Workarounds fuer Datenbanken ohne native NULLS FIRST/LAST Syntax
Fuer MySQL und SQL Server ist der gaengige Workaround, eine zusaetzliche berechnete Spalte in die ORDER BY-Klausel einzufuegen, die zuerst danach sortiert, ob ein Wert NULL ist, und erst danach nach dem eigentlichen Wert. In MySQL nutzt man dafuer typischerweise ORDER BY column IS NULL, column, da der boolesche Ausdruck column IS NULL zu 0 fuer nicht-NULL-Werte und zu 1 fuer NULL-Werte ausgewertet wird, was NULL-Werte in einer aufsteigenden Sortierung automatisch ans Ende schiebt.
SQL Server kennt keinen direkten IS NULL-als-Ganzzahl-Ausdruck in dieser Form, daher wird dort typischerweise mit einem CASE WHEN column IS NULL THEN 1 ELSE 0 END als zusaetzlicher Sortierschluessel gearbeitet, funktional identisch zum MySQL-Ansatz, aber mit deutlich mehr Schreibaufwand. Beide Workarounds sind vollstaendig portabel und funktionieren auch auf PostgreSQL und Oracle, weshalb sie sich fuer datenbankuebergreifenden Code anbieten, selbst wenn NULLS FIRST/NULLS LAST auf diesen Systemen verfuegbar waeren.
-- MySQL workaround: boolean expression as a secondary sort key
SELECT id, discount_percent
FROM products
ORDER BY discount_percent IS NULL, discount_percent ASC;
-- IS NULL evaluates to 0 (false) or 1 (true), pushing NULLs to the end
-- SQL Server workaround: CASE expression as a secondary sort key
SELECT id, discount_percent
FROM products
ORDER BY
CASE WHEN discount_percent IS NULL THEN 1 ELSE 0 END,
discount_percent ASC;
-- Portable pattern: works on all four databases without native syntax
5. COALESCE als ANSI Standard und seine Kurzschluss-Auswertung
Die Funktion COALESCE(a, b, c, ...) ist Teil des ANSI-SQL-Standards und wird von allen vier besprochenen Datenbanken identisch unterstuetzt. Sie akzeptiert eine beliebige Anzahl an Argumenten und gibt den ersten Wert zurueck, der nicht NULL ist, oder NULL, wenn tatsaechlich alle Argumente NULL sind. Wichtig fuer die Performance und fuer Nebeneffekte in Ausdruecken: COALESCE() wertet die Argumente von links nach rechts aus und stoppt, sobald das erste Nicht-NULL-Argument gefunden wurde, eine echte Kurzschluss-Auswertung, die spaeter stehende Ausdruecke gar nicht erst ausfuehrt.
Diese Kurzschluss-Eigenschaft ist besonders relevant, wenn spaetere Argumente rechenintensive Subqueries oder Funktionsaufrufe enthalten, da diese bei einem fruehen Treffer uebersprungen werden. Da COALESCE() in allen vier Datenbanken identisch funktioniert, ist es die erste Wahl fuer portablen Code, waehrend die proprietaeren Alternativen im naechsten Abschnitt nur dort sinnvoll sind, wo eine bewusst datenbankspezifische Optimierung gewuenscht ist.
-- COALESCE: identical syntax and behavior across all four databases
SELECT id, COALESCE(discount_percent, 0) AS discount_or_zero
FROM products;
-- Multiple fallback values, evaluated left to right, short-circuits early
SELECT id, COALESCE(preferred_name, display_name, username, 'Unknown')
AS resolved_name
FROM customers;
-- If preferred_name is not NULL, display_name and username are never evaluated
6. Proprietaere Alternativen: IFNULL, ISNULL, NVL im Vergleich
Neben COALESCE() bietet jede Datenbank eine eigene, aeltere, proprietaere Kurzform mit exakt zwei Argumenten. MySQL nutzt IFNULL(ausdruck, ersatzwert), SQL Server ISNULL(ausdruck, ersatzwert), und Oracle NVL(ausdruck, ersatzwert). PostgreSQL verzichtet komplett auf eine solche proprietaere Kurzform und setzt konsequent auf COALESCE() als einzigen Weg, was PostgreSQL in diesem Bereich zur konsistentesten der vier Datenbanken macht.
Ein wichtiger, oft uebersehener Unterschied betrifft die Typkonvertierung: SQL Servers ISNULL() leitet den Rueckgabetyp vom ersten Argument ab, was bei unterschiedlichen Datentypen zwischen erstem und zweitem Argument zu stillen Kuerzungen fuehren kann, waehrend COALESCE() in SQL Server den allgemeineren Typ nach Standard-Typumwandlungsregeln waehlt. Diese Diskrepanz zwischen ISNULL() und COALESCE() innerhalb desselben SQL-Server-Systems ist ein haeufiger, schwer zu findender Bug, wenn beide Funktionen unreflektiert austauschbar verwendet werden.
-- MySQL: IFNULL(), exactly two arguments
SELECT id, IFNULL(discount_percent, 0) FROM products;
-- SQL Server: ISNULL(), return type inferred from the FIRST argument
SELECT id, ISNULL(discount_percent, 0) FROM products;
-- Warning: ISNULL(NULL, 'some long string') may silently truncate
-- if the inferred type from a typed NULL is shorter than the replacement
-- Oracle: NVL(), exactly two arguments, similar to IFNULL
SELECT id, NVL(discount_percent, 0) FROM products;
-- PostgreSQL: no proprietary shorthand, COALESCE() is the only native option
SELECT id, COALESCE(discount_percent, 0) FROM products;
7. NULL in Vergleichsoperatoren und die Drei-Wertige-Logik kurz eingeordnet
Neben Sortierung und Ersatzwerten spielt NULL auch bei direkten Vergleichen eine Sonderrolle, die in allen vier Datenbanken identisch geregelt ist: ein Vergleich wie spalte = NULL liefert niemals TRUE, sondern immer UNKNOWN, selbst wenn die Spalte tatsaechlich NULL enthaelt. Diese sogenannte Drei-Wertige-Logik mit den Zustaenden TRUE, FALSE und UNKNOWN ist Teil des ANSI-Standards und in MySQL, PostgreSQL, SQL Server und Oracle konsistent implementiert, weshalb fuer NULL-Pruefungen immer IS NULL oder IS NOT NULL verwendet werden muss.
Diese Konsistenz bei der Drei-Wertigen-Logik steht im deutlichen Kontrast zur Inkonsistenz bei Sortierung und Ersatzwerten und zeigt, dass die Datenbanken beim eigentlichen ANSI-Kernstandard sehr genau uebereinstimmen, waehrend Bereiche mit historisch gewachsener, herstellerspezifischer Erweiterung wie NULLS FIRST oder proprietaere Ersatzwert-Funktionen deutlich staerker divergieren. Dieser Artikel behandelt bewusst nur Sortierung und Ersatzwerte im Detail, waehrend die vollstaendige Drei-Wertige-Logik in Aggregatfunktionen einem eigenen Artikel dieses Blogs vorbehalten bleibt.
8. Portable Patterns fuer NULL-Handling in Anwendungscode
Fuer Anwendungen, die mehrere Datenbanken unterstuetzen muessen, empfiehlt sich konsequent COALESCE() statt der proprietaeren Kurzformen, da es ohne Anpassung auf allen vier Systemen identisch funktioniert. Fuer die Sortierreihenfolge von NULL-Werten ist der portable CASE WHEN column IS NULL THEN 1 ELSE 0 END-Ansatz aus Abschnitt vier die sicherste Wahl, da er unabhaengig vom jeweiligen Standardverhalten der Zieldatenbank funktioniert und explizit im Code dokumentiert, welches Verhalten tatsaechlich gewuenscht ist.
ORMs wie Doctrine, Eloquent oder SQLAlchemy bieten in aktuellen Versionen bereits eine coalesce()-Query-Builder-Methode, die intern die native Syntax der Zieldatenbank generiert. Fuer NULLS FIRST/NULLS LAST bieten nicht alle ORMs eine eingebaute Abstraktion, weshalb sich hier ein automatisierter Test lohnt, der die tatsaechliche Sortierreihenfolge von NULL-Werten gegen jede unterstuetzte Zieldatenbank explizit prueft, statt sich auf das implizite Standardverhalten zu verlassen.
9. NULL-Handling-Funktionen im direkten Vergleich
Die folgende Tabelle fasst die zentralen Unterschiede bei Sortierung und Ersatzwert-Funktionen zusammen.
| Datenbank | NULL bei ASC (Standard) | NULLS FIRST/LAST | Proprietaere Ersatzfunktion |
|---|---|---|---|
| MySQL | Zuerst | Nicht unterstuetzt | IFNULL() |
| PostgreSQL | Zuletzt | Unterstuetzt | Keine, nur COALESCE() |
| SQL Server | Zuerst | Nicht unterstuetzt | ISNULL() |
| Oracle | Zuletzt | Unterstuetzt | NVL() |
Auffaellig ist die klare Zweiteilung: PostgreSQL und Oracle teilen sich sowohl das Standardverhalten (NULL zuletzt bei ASC) als auch die native NULLS FIRST/NULLS LAST-Unterstuetzung, waehrend MySQL und SQL Server beide auf das entgegengesetzte Standardverhalten und denselben Workaround angewiesen sind.
Mironsoft
SQL-Portabilitaet, Query-Audits und Datenbank-Migrationen
NULL-Handling, das auf jeder Zieldatenbank konsistent bleibt?
Wir pruefen bestehende Sortierlogik und Ersatzwert-Funktionen auf stille Verhaltensaenderungen bei Migrationen und bauen portable Patterns, die auf MySQL, PostgreSQL, SQL Server und Oracle gleichermassen korrekt funktionieren.
Migrations-Audit
Pruefung von ORDER BY-Klauseln auf abweichendes NULL-Standardverhalten
Code-Review
ISNULL vs. COALESCE Typkonvertierungsrisiken in SQL Server aufspueren
Abstraktionsschicht
Portable Sortier- und Ersatzwert-Patterns fuer mehrere Datenbanken
10. Zusammenfassung
Das NULL-Verhalten bei Sortierung unterscheidet sich klar zwischen den Datenbank-Familien: PostgreSQL und Oracle sortieren NULL standardmaessig ans Ende bei aufsteigender Sortierung und bieten native NULLS FIRST/NULLS LAST-Steuerung, waehrend MySQL und SQL Server NULL standardmaessig an den Anfang stellen und auf einen CASE- beziehungsweise IS NULL-Workaround angewiesen sind. Bei Ersatzwerten ist COALESCE() die einzige Funktion, die auf allen vier Systemen identisch funktioniert, waehrend IFNULL(), ISNULL() und NVL() proprietaere, nicht austauschbare Kurzformen sind.
Fuer portablen Code lohnt sich konsequent COALESCE() statt der proprietaeren Alternativen und ein expliziter, getesteter Sortier-Workaround statt Verlass auf implizites Standardverhalten. Wer diese NULL-Unterschiede bei Sortierung und Ersatzwerten kennt, vermeidet stille Verhaltensaenderungen bei Datenbankwechseln, die sonst erst durch fehlerhafte Reports oder falsch sortierte Listen auffallen.
NULL-Sortierung und COALESCE im Datenbankvergleich — Das Wichtigste auf einen Blick
PostgreSQL / Oracle
NULL zuletzt bei ASC, native NULLS FIRST/NULLS LAST-Steuerung verfuegbar.
MySQL / SQL Server
NULL zuerst bei ASC, Workaround ueber IS NULL oder CASE als Sortierschluessel.
COALESCE()
ANSI-Standard, identisch auf allen vier Systemen, mit Kurzschluss-Auswertung.
IFNULL / ISNULL / NVL
Proprietaer und nicht austauschbar, ISNULL in SQL Server mit Typkonvertierungsrisiko.