Aufwärmen · Aufgabe 1 von 7
// B2.4 · ca. 30 Min. · Einstieg
NULL, IS NULL und COALESCE
Nach dieser Lektion finden Sie die fehlenden Werte einer Tabelle, verhindern, dass sie still Zeilen verschwinden lassen, und zeigen an ihrer Stelle einen sinnvollen Ersatzwert.
Danach können Sie
- Erklären, was NULL bedeutet, und Vergleiche und WHERE-Bedingungen vorhersagen, die auf ein NULL treffen
- Fehlende Werte mit IS NULL, IS NOT NULL und IS DISTINCT FROM finden und die NOT-IN-Falle vermeiden
- NULL mit COALESCE ersetzen, einen Wert mit NULLIF zu NULL machen und Text mit concat() verbinden
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es voraus, bevor Sie weiterlesen. Genau ein Mitglied, Linus, hat keine E-Mail. Was liefert dies?
SELECT count(*) FROM members WHERE email = NULL;Üben · Aufgabe 3 von 7
Ergänzen Sie das Schlüsselwort, damit die Abfrage das Mitglied ohne E-Mail findet.
SELECT name FROM members WHERE email ____ NULL;SELECT name FROM members WHERE email NULL;Üben · Aufgabe 4 von 7
Ordnen Sie jedem Ausdruck sein Ergebnis zu.
Üben · Aufgabe 5 von 7
Zwei Ausleihen kamen zurück, am 2026-09-10 und am 2026-09-20; die anderen drei sind noch unterwegs (returned_on ist NULL). Was liefert dies?
SELECT count(*) FROM loans WHERE returned_on > '2026-09-15';Denksport · Aufgabe 6 von 7
Knobelaufgabe. Ada und Linus wohnen in Berlin, Grace in München (Munich), Margarets Stadt ist NULL. Jemand hat NULL in die Liste geschrieben, „um die Mitglieder ohne Stadt auszuschließen“. Was liefert dies?
SELECT count(*) FROM members WHERE city NOT IN ('Munich', NULL);Anwenden · Aufgabe 7 von 7
Mini-Aufgabe. Schreiben Sie mit der Bibliothek des Beispiels zwei Abfragen: jedes Mitglied mit Name, E-Mail und Stadt, wobei eine fehlende E-Mail als (none) und eine fehlende Stadt als unknown erscheint; und die ids der Ausleihen, die noch offen sind. Ersetzen Sie dann IS NULL durch = NULL, sagen Sie das Ergebnis voraus und führen Sie es aus.
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Selbst programmieren
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Die Lücken der Bibliothek finden und füllen
setup.sql lädt die Bibliothek aus Modul B1: Bücher, Mitglieder und Ausleihen. main.sql findet die Mitglieder mit einem fehlenden Wert, zeigt eine Kontaktliste mit gefüllten Lücken und listet die Ausleihen, die noch offen sind. Auf Ihrem Computer: psql -X -q -v ON_ERROR_STOP=1 -f setup.sql -f main.sql.
main.sql
-- 1. Who is missing an email or a city?
SELECT name, email, city
FROM members
WHERE email IS NULL OR city IS NULL
ORDER BY id;
-- 2. The same gaps, filled for display.
SELECT name,
coalesce(email, '(no email)') AS contact,
name || ' (' || city || ')' AS with_pipes,
concat(name, ' (', city, ')') AS with_concat
FROM members
ORDER BY id;
-- 3. Loans that are still open.
SELECT id, book_id, member_id, loaned_on
FROM loans
WHERE returned_on IS NULL
ORDER BY id;
setup.sql
CREATE TABLE books (
id integer,
title text,
author text,
year integer,
genre text,
copies integer
);
INSERT INTO books VALUES
(1, 'Dune', 'Frank Herbert', 1965, 'sci-fi', 2),
(2, 'Emma', 'Jane Austen', 1815, 'classic', 1),
(3, 'Kindred', 'Octavia E. Butler', 1979, 'sci-fi', 1),
(4, 'Beloved', 'Toni Morrison', 1987, 'fiction', 1),
(5, 'The Hobbit', 'J. R. R. Tolkien', 1937, 'fantasy', 3),
(6, 'Neuromancer', 'William Gibson', 1984, 'sci-fi', 1);
CREATE TABLE members (
id integer,
name text,
email text,
city text,
joined date
);
INSERT INTO members VALUES
(1, 'Ada', 'ada@example.com', 'Berlin', '2025-01-15'),
(2, 'Grace', 'grace@example.com', 'Munich', '2025-03-02'),
(3, 'Linus', NULL, 'Berlin', '2026-02-10'),
(4, 'Margaret', 'margaret@example.com', NULL, '2026-05-20');
CREATE TABLE loans (
id integer,
book_id integer,
member_id integer,
loaned_on date,
returned_on date
);
INSERT INTO loans VALUES
(1, 1, 1, '2026-09-01', '2026-09-10'),
(2, 3, 1, '2026-09-12', NULL),
(3, 2, 2, '2026-09-05', '2026-09-20'),
(4, 1, 3, '2026-09-15', NULL),
(5, 6, 2, '2026-09-18', NULL);
Ausführen mit
psql -X -q -v ON_ERROR_STOP=1 -f setup.sql -f main.sqlAusgabe
name | email | city
----------+----------------------+--------
Linus | | Berlin
Margaret | margaret@example.com |
(2 rows)
name | contact | with_pipes | with_concat
----------+----------------------+----------------+----------------
Ada | ada@example.com | Ada (Berlin) | Ada (Berlin)
Grace | grace@example.com | Grace (Munich) | Grace (Munich)
Linus | (no email) | Linus (Berlin) | Linus (Berlin)
Margaret | margaret@example.com | | Margaret ()
(4 rows)
id | book_id | member_id | loaned_on
----+---------+-----------+------------
2 | 3 | 1 | 2026-09-12
4 | 1 | 3 | 2026-09-15
5 | 6 | 2 | 2026-09-18
(3 rows)- psql zeigt NULL als leere Zelle: Linus’ E-Mail und Margarets Stadt im ersten Ergebnis.
- coalesce() setzt (no email) ein, wo die E-Mail NULL ist, und lässt die anderen E-Mails, wie sie sind.
- Mit || macht ein einziger NULL-Teil das ganze Label zu NULL, deshalb ist Margarets Zelle with_pipes leer. concat() überspringt das NULL und liefert Margaret ().
- returned_on IS NULL findet die drei offenen Ausleihen; returned_on = NULL fände keine.
Ändern und ausführen
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser PostgreSQL herunter (bis zu 10.1 MB) und speichert es im Cache. Jeder Lauf beginnt mit einer leeren Datenbank. Ihr Code bleibt auf Ihrem Gerät.
Übungen
Übung 1 von 2
Eine Kontaktliste und ein Ausleihstatus ohne Lücken
Schreiben Sie zwei Abfragen. Erstens: Name, E-Mail und Stadt jedes Mitglieds, nach id sortiert, wobei eine fehlende E-Mail als (no email) und eine fehlende Stadt als unknown erscheint; die Spaltennamen bleiben name, email und city. Zweitens: id und loaned_on jeder Ausleihe, dazu eine Spalte returned, die das Rückgabedatum zeigt oder open, wenn es keines gibt, nach id sortiert.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser PostgreSQL herunter (bis zu 10.1 MB) und speichert es im Cache. Jeder Lauf beginnt mit einer leeren Datenbank. Ihr Code bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
coalesce(email, '(no email)') AS email behält den Spaltennamen email.
Hinweis 2
returned_on ist ein date und 'open' ist Text: coalesce braucht einen Typ für beide.
Hinweis 3
Wandeln Sie das Datum zuerst in Text um: coalesce(returned_on::text, 'open').
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
SELECT name,
coalesce(email, '(no email)') AS email,
coalesce(city, 'unknown') AS city
FROM members
ORDER BY id;
SELECT id, loaned_on, coalesce(returned_on::text, 'open') AS returned
FROM loans
ORDER BY id;
Auf dem eigenen Computer ausführen
Installieren Sie PostgreSQL 18 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.sql
-- setup.sql has loaded books, members and loans.
SELECT * FROM members ORDER BY id;
test.sql
-- test: Die Kontaktliste füllt die Lücken, danach zeigt jede Ausleihe ihr Rückgabedatum oder open
-- output:
-- name | email | city
-- ----------+----------------------+---------
-- Ada | ada@example.com | Berlin
-- Grace | grace@example.com | Munich
-- Linus | (no email) | Berlin
-- Margaret | margaret@example.com | unknown
-- (4 rows)
--
-- id | loaned_on | returned
-- ----+------------+------------
-- 1 | 2026-09-01 | 2026-09-10
-- 2 | 2026-09-12 | open
-- 3 | 2026-09-05 | 2026-09-20
-- 4 | 2026-09-15 | open
-- 5 | 2026-09-18 | open
-- (5 rows)
setup.sql
CREATE TABLE books (
id integer,
title text,
author text,
year integer,
genre text,
copies integer
);
INSERT INTO books VALUES
(1, 'Dune', 'Frank Herbert', 1965, 'sci-fi', 2),
(2, 'Emma', 'Jane Austen', 1815, 'classic', 1),
(3, 'Kindred', 'Octavia E. Butler', 1979, 'sci-fi', 1),
(4, 'Beloved', 'Toni Morrison', 1987, 'fiction', 1),
(5, 'The Hobbit', 'J. R. R. Tolkien', 1937, 'fantasy', 3),
(6, 'Neuromancer', 'William Gibson', 1984, 'sci-fi', 1);
CREATE TABLE members (
id integer,
name text,
email text,
city text,
joined date
);
INSERT INTO members VALUES
(1, 'Ada', 'ada@example.com', 'Berlin', '2025-01-15'),
(2, 'Grace', 'grace@example.com', 'Munich', '2025-03-02'),
(3, 'Linus', NULL, 'Berlin', '2026-02-10'),
(4, 'Margaret', 'margaret@example.com', NULL, '2026-05-20');
CREATE TABLE loans (
id integer,
book_id integer,
member_id integer,
loaned_on date,
returned_on date
);
INSERT INTO loans VALUES
(1, 1, 1, '2026-09-01', '2026-09-10'),
(2, 3, 1, '2026-09-12', NULL),
(3, 2, 2, '2026-09-05', '2026-09-20'),
(4, 1, 3, '2026-09-15', NULL),
(5, 6, 2, '2026-09-18', NULL);
psql führt die Dateien auf Ihrem eigenen PostgreSQL-Server aus. Nehmen Sie eine leere Datenbank, die Sie wegwerfen können: Hängen Sie -d und ihren Namen an den Befehl an.
Programm ausführen:
psql -X -q -v ON_ERROR_STOP=1 -f setup.sql -f main.sqlFür die Prüfungen gibt es auf Ihrem Computer noch keinen Befehl. Sie stehen in test.sql: Jede Prüfabfrage gibt t aus, wenn sie besteht.
Übung 2 von 2
Alle außerhalb Berlins
Die Vorlage soll jedes Mitglied auflisten, das nicht in Berlin wohnt, mit Name und Stadt, nach id sortiert. Sie findet Grace, übersieht aber Margaret, deren Stadt unbekannt und damit sicher nicht als Berlin eingetragen ist. Reparieren Sie die Bedingung, sodass beide erscheinen. Probieren Sie beide Reparaturen: IS DISTINCT FROM und ein zusätzliches OR … IS NULL.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser PostgreSQL herunter (bis zu 10.1 MB) und speichert es im Cache. Jeder Lauf beginnt mit einer leeren Datenbank. Ihr Code bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
Für Margaret ist city <> 'Berlin' NULL, nicht wahr, deshalb verwirft WHERE sie.
Hinweis 2
IS DISTINCT FROM behandelt NULL als eigenen Wert: NULL IS DISTINCT FROM 'Berlin' ist true.
Hinweis 3
Oder behalten Sie <> und ergänzen den fehlenden Fall: city <> 'Berlin' OR city IS NULL.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
-- Members who do not live in Berlin.
SELECT name, city
FROM members
WHERE city IS DISTINCT FROM 'Berlin'
ORDER BY id;
Auf dem eigenen Computer ausführen
Installieren Sie PostgreSQL 18 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.sql
-- Members who do not live in Berlin.
SELECT name, city
FROM members
WHERE city <> 'Berlin'
ORDER BY id;
test.sql
-- test: Grace und Margaret erscheinen, Margaret mit leerer Stadt
-- output:
-- name | city
-- ----------+--------
-- Grace | Munich
-- Margaret |
-- (2 rows)
setup.sql
CREATE TABLE books (
id integer,
title text,
author text,
year integer,
genre text,
copies integer
);
INSERT INTO books VALUES
(1, 'Dune', 'Frank Herbert', 1965, 'sci-fi', 2),
(2, 'Emma', 'Jane Austen', 1815, 'classic', 1),
(3, 'Kindred', 'Octavia E. Butler', 1979, 'sci-fi', 1),
(4, 'Beloved', 'Toni Morrison', 1987, 'fiction', 1),
(5, 'The Hobbit', 'J. R. R. Tolkien', 1937, 'fantasy', 3),
(6, 'Neuromancer', 'William Gibson', 1984, 'sci-fi', 1);
CREATE TABLE members (
id integer,
name text,
email text,
city text,
joined date
);
INSERT INTO members VALUES
(1, 'Ada', 'ada@example.com', 'Berlin', '2025-01-15'),
(2, 'Grace', 'grace@example.com', 'Munich', '2025-03-02'),
(3, 'Linus', NULL, 'Berlin', '2026-02-10'),
(4, 'Margaret', 'margaret@example.com', NULL, '2026-05-20');
CREATE TABLE loans (
id integer,
book_id integer,
member_id integer,
loaned_on date,
returned_on date
);
INSERT INTO loans VALUES
(1, 1, 1, '2026-09-01', '2026-09-10'),
(2, 3, 1, '2026-09-12', NULL),
(3, 2, 2, '2026-09-05', '2026-09-20'),
(4, 1, 3, '2026-09-15', NULL),
(5, 6, 2, '2026-09-18', NULL);
psql führt die Dateien auf Ihrem eigenen PostgreSQL-Server aus. Nehmen Sie eine leere Datenbank, die Sie wegwerfen können: Hängen Sie -d und ihren Namen an den Befehl an.
Programm ausführen:
psql -X -q -v ON_ERROR_STOP=1 -f setup.sql -f main.sqlFür die Prüfungen gibt es auf Ihrem Computer noch keinen Befehl. Sie stehen in test.sql: Jede Prüfabfrage gibt t aus, wenn sie besteht.
Häufige Fehler
Ein Text als Ersatz für eine Zahlenspalte
SELECT title, coalesce(year, 'unknown') AS year
FROM books;
Was psql ausgibt
ERROR: invalid input syntax for type integer: "unknown"Warum, und die Lösung
coalesce() liefert einen Typ für alle seine Argumente. year ist ein integer, also versucht PostgreSQL, 'unknown' als integer zu lesen, und scheitert. Machen Sie beide Seiten zu Text: coalesce(year::text, 'unknown'). Oder wählen Sie einen Ersatzwert vom Typ der Spalte, etwa coalesce(copies, 0).
IS als allgemeines „gleich“
SELECT name FROM members WHERE city IS 'Berlin';
Was psql ausgibt
ERROR: syntax error at or near "'Berlin'"Warum, und die Lösung
IS funktioniert nur mit einer festen Reihe von Wörtern: IS NULL, IS NOT NULL, IS TRUE, IS DISTINCT FROM und einigen mehr. Es ist keine andere Schreibweise für =. Für einen Wert schreiben Sie city = 'Berlin'; soll NULL als eigener Wert gelten, city IS NOT DISTINCT FROM 'Berlin'.
Durch eine Spalte teilen, die 0 sein kann
SELECT member, pages * 60 / minutes AS pages_per_hour
FROM readings;
Was psql ausgibt
ERROR: division by zeroWarum, und die Lösung
Eine einzige Zeile mit minutes = 0 bricht die ganze Abfrage ab, und es erscheint gar keine Zeile. Teilen Sie stattdessen durch NULLIF(minutes, 0): Für diese Zeile ist der Teiler NULL, und das Ergebnis ist NULL statt eines Fehlers. Braucht der Bericht einen Ersatzwert, setzen Sie ihn danach mit coalesce().
PostgreSQL im Browser: PGlite 0.5.8 (PostgreSQL 18.3), Apache-2.0 und PostgreSQL License. Lizenz und Quellcode
Abschlussquiz
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.