Zum Inhalt springen
aviral gupta

// B1.4 · ca. 32 Min. · Einstieg

Projekt: die Bibliotheksdatenbank

Nach diesem Projekt haben Sie die Bibliotheksdatenbank, mit der der ganze Kurs arbeitet: books, members und loans, mit passenden Typen angelegt, befüllt und geprüft.

Lektion 4 von 4 in B1 Erste Schritte

Ende des Moduls

Danach können Sie

  • Für jede Spalte von books, members und loans einen Typ wählen und die drei Tabellen anlegen
  • Die Zeilen mit mehrzeiligen INSERT-Anweisungen laden und NULL schreiben, wo ein Wert unbekannt ist
  • Das Ergebnis mit SELECT * … ORDER BY und count(*) prüfen und das Skript wiederholbar machen
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen: Welcher Typ passt zu loaned_on, dem Tag, an dem ein Buch ausgeliehen wurde?

  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es voraus, bevor Sie weiterlesen: Drei dieser fünf Ausleihen haben kein Rückgabedatum. Was liefert die letzte Anweisung?

    CREATE TABLE loans (id integer, loaned_on date, returned_on date);
    INSERT INTO loans VALUES
      (1, '2026-09-01', '2026-09-10'),
      (2, '2026-09-12', NULL),
      (3, '2026-09-05', '2026-09-20'),
      (4, '2026-09-15', NULL),
      (5, '2026-09-18', NULL);
    SELECT count(*) FROM loans;
  3. Üben · Aufgabe 3 von 7

    Ordnen Sie jeder Spalte den passenden Typ zu.

  4. Üben · Aufgabe 4 von 7

    Linus hat keine E-Mail-Adresse. Ergänzen Sie den Wert, der „unbekannt“ bedeutet.

    INSERT INTO members VALUES (3, 'Linus', ____, 'Berlin', '2026-02-10');
    INSERT INTO members VALUES (3, 'Linus', , 'Berlin', '2026-02-10');
  5. Üben · Aufgabe 5 von 7

    Bringen Sie die Teile eines wiederholbaren Aufbauskripts in die Reihenfolge, in der sie laufen müssen.

    1. 1.INSERT INTO books VALUES (1, 'Dune', …), (2, 'Emma', …);
    2. 2.CREATE TABLE books (id integer, title text, …);
    3. 3.SELECT count(*) FROM books;
    4. 4.DROP TABLE IF EXISTS books;
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Die Tabelle loans ist leer. Dieses INSERT hat drei Zeilen, und die zweite enthält einen Tag, den es nicht gibt. Wie viele Zeilen enthält loans danach?

    INSERT INTO loans VALUES
      (1, 1, 1, '2026-09-01', '2026-09-10'),
      (2, 3, 1, '2026-09-31', NULL),
      (3, 2, 2, '2026-09-05', '2026-09-20');
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Gehen Sie vom books-Skript des Beispiels aus. Fügen Sie zwei Bücher, die Sie mögen, mit einem weiteren INSERT mit zwei Zeilen hinzu, ids 7 und 8, und enden Sie mit SELECT count(*) FROM books;. Führen Sie es aus: Die Anzahl muss 8 sein. Lassen Sie dann ein Komma zwischen Ihren zwei Zeilen weg und lesen Sie den Fehler.

    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 Tabelle books, gebaut und geprüft

Die erste Tabelle der Bibliothek, so wie das ganze Projekt arbeitet: alte Tabelle löschen, sie mit einem Typ pro Spalte anlegen, alle Zeilen mit einem INSERT laden, dann ansehen und zählen. DROP TABLE IF EXISTS gibt nur einen Hinweis aus, wenn es noch keine Tabelle gibt, wie bei jedem Lauf hier. Auf Ihrem Computer speichern Sie es als main.sql und führen psql -X -q -v ON_ERROR_STOP=1 -f main.sql aus, so oft Sie wollen.

main.sql

-- The library, step 1: books.
DROP TABLE IF EXISTS books;

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);

SELECT * FROM books ORDER BY id;

SELECT count(*) AS books FROM books;

Ausführen mit

psql -X -q -v ON_ERROR_STOP=1 -f main.sql

Ausgabe

 id |    title    |      author       | year |  genre  | copies
----+-------------+-------------------+------+---------+--------
  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
(6 rows)

 books
-------
     6
(1 row)
  • Ein INSERT fügt alle sechs Zeilen hinzu: ein Komma zwischen den Zeilen, ein Semikolon am Ende.
  • id, year und copies sind integer, deshalb richtet psql sie rechtsbündig aus; Text steht linksbündig.
  • ORDER BY id zeigt die Zeilen nach id geordnet; ohne es verspricht SQL keine Reihenfolge.
  • count(*) zählt die Zeilen: 6, so viele, wie das INSERT hinzugefügt hat.
  • Der Hinweis von DROP TABLE IF EXISTS gehört nicht zum Ergebnis; psql gibt ihn getrennt aus, als Meldung.
Ä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

Schritt 2: die Mitglieder

Legen Sie die Tabelle members mit den Spalten id, name, email, city und joined an, jede mit einem passenden Typ, und laden Sie die vier Mitglieder aus der Vorlage mit einem INSERT. Linus hat keine E-Mail und Margaret keine Stadt: Schreiben Sie NULL. Enden Sie mit SELECT * FROM members ORDER BY id;.

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
  1. Hinweis 1

    id ist integer, joined ist date, die anderen drei Spalten sind text.

  2. Hinweis 2

    Ein INSERT INTO members VALUES mit vier Zeilen in Klammern, durch Kommas getrennt. Daten stehen in Anführungszeichen: '2025-01-15'.

  3. Hinweis 3

    Die Zeile von Linus: (3, 'Linus', NULL, 'Berlin', '2026-02-10'). NULL steht ohne Anführungszeichen.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

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');

SELECT * FROM members 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

-- Create the table members (id, name, email, city, joined)
-- and add these four members in one INSERT:
--   1  Ada       ada@example.com       Berlin  2025-01-15
--   2  Grace     grace@example.com     Munich  2025-03-02
--   3  Linus     (no email)            Berlin  2026-02-10
--   4  Margaret  margaret@example.com  (no city)  2026-05-20
-- Then list them, ordered by id.

test.sql

-- test: members hat die Spalten id (integer), name, email, city (text) und joined (date)
SELECT count(*) = 5 FROM information_schema.columns
WHERE table_name = 'members'
  AND ((column_name = 'id' AND data_type = 'integer')
    OR (column_name IN ('name', 'email', 'city') AND data_type = 'text')
    OR (column_name = 'joined' AND data_type = 'date'));

-- test: Die Tabelle enthält vier Mitglieder
SELECT count(*) = 4 FROM members;

-- test: Linus hat keine E-Mail (NULL, nicht der Text 'NULL')
SELECT EXISTS (SELECT 1 FROM members WHERE id = 3 AND name = 'Linus' AND email IS NULL AND city = 'Berlin' AND joined = '2026-02-10');

-- test: Margaret hat keine Stadt (NULL)
SELECT EXISTS (SELECT 1 FROM members WHERE id = 4 AND name = 'Margaret' AND email = 'margaret@example.com' AND city IS NULL AND joined = '2026-05-20');

-- test: Das Skript listet die vier Mitglieder auf, nach id sortiert
-- output:
--  id |   name   |        email         |  city  |   joined
-- ----+----------+----------------------+--------+------------
--   1 | Ada      | ada@example.com      | Berlin | 2025-01-15
--   2 | Grace    | grace@example.com    | Munich | 2025-03-02
--   3 | Linus    |                      | Berlin | 2026-02-10
--   4 | Margaret | margaret@example.com |        | 2026-05-20
-- (4 rows)

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 main.sql

Fü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

Schritt 3: die Ausleihen und eine Zählung von allem

setup.sql hat books und members angelegt. Legen Sie die Tabelle loans (id, book_id, member_id, loaned_on, returned_on) an und laden Sie die fünf Ausleihen aus der Vorlage; die offenen haben kein Rückgabedatum. Zählen Sie dann die Zeilen aller drei Tabellen, eine Abfrage pro Tabelle, mit AS benannt als books, members und loans.

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
  1. Hinweis 1

    Die drei ids sind integer; loaned_on und returned_on sind date.

  2. Hinweis 2

    Eine offene Ausleihe hat NULL als Rückgabedatum: (2, 3, 1, '2026-09-12', NULL).

  3. Hinweis 3

    SELECT count(*) AS books FROM books; dann dasselbe für members und loans.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

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);

SELECT count(*) AS books FROM books;
SELECT count(*) AS members FROM members;
SELECT count(*) AS loans FROM loans;
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 created books and members.
-- Create loans (id, book_id, member_id, loaned_on, returned_on)
-- and add these five loans in one INSERT:
--   1  book 1  member 1  2026-09-01  2026-09-10
--   2  book 3  member 1  2026-09-12  (open)
--   3  book 2  member 2  2026-09-05  2026-09-20
--   4  book 1  member 3  2026-09-15  (open)
--   5  book 6  member 2  2026-09-18  (open)
-- Then count the rows of books, members and loans.

test.sql

-- test: loans hat integer-ids und zwei date-Spalten
SELECT count(*) = 5 FROM information_schema.columns
WHERE table_name = 'loans'
  AND ((column_name IN ('id', 'book_id', 'member_id') AND data_type = 'integer')
    OR (column_name IN ('loaned_on', 'returned_on') AND data_type = 'date'));

-- test: Die Tabelle enthält fünf Ausleihen
SELECT count(*) = 5 FROM loans;

-- test: Die Ausleihen 2, 4 und 5 sind offen (returned_on ist NULL)
SELECT (SELECT count(*) FROM loans WHERE returned_on IS NULL AND id IN (2, 4, 5)) = 3
   AND (SELECT count(*) FROM loans WHERE returned_on IS NULL) = 3;

-- test: Ausleihe 4 ist Buch 1, am 2026-09-15 an Mitglied 3 verliehen
SELECT EXISTS (SELECT 1 FROM loans WHERE id = 4 AND book_id = 1 AND member_id = 3 AND loaned_on = '2026-09-15');

-- test: Das Skript gibt die drei Anzahlen aus: 6, 4 und 5
-- output:
--  books
-- -------
--      6
-- (1 row)
--
--  members
-- ---------
--        4
-- (1 row)
--
--  loans
-- -------
--      5
-- (1 row)

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');

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.sql

Fü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

Das Skript ein zweites Mal ausführen

CREATE TABLE books (
  id integer,
  title text
);
INSERT INTO books VALUES (1, 'Dune'), (2, 'Emma');

Was psql ausgibt

ERROR:  relation "books" already exists

Warum, und die Lösung

In Ihrer eigenen Datenbank hat der erste Lauf books angelegt, und die Tabelle ist noch da. Ein zweites CREATE TABLE books scheitert, und ON_ERROR_STOP beendet den Lauf. Beginnen Sie das Skript mit DROP TABLE IF EXISTS books;, dann entfernt jeder Lauf zuerst die alte Tabelle und legt sie danach neu an.

'NULL' in Anführungszeichen

CREATE TABLE loans (id integer, loaned_on date, returned_on date);
INSERT INTO loans VALUES
  (1, '2026-09-01', '2026-09-10'),
  (2, '2026-09-12', 'NULL');

Was psql ausgibt

ERROR:  invalid input syntax for type date: "NULL"

Warum, und die Lösung

In Anführungszeichen ist 'NULL' Text, die vier Buchstaben N, U, L, L, und eine date-Spalte kann sie nicht als Tag lesen. Schreiben Sie NULL ohne Anführungszeichen, um zu sagen, dass der Wert unbekannt ist. Vorsicht bei text-Spalten: Dort wird 'NULL' angenommen und als Wort gespeichert, das später wie ein Wert aussieht.

Ein fehlendes Komma zwischen Zeilen

CREATE TABLE books (id integer, title text);
INSERT INTO books VALUES
  (1, 'Dune')
  (2, 'Emma');

Was psql ausgibt

ERROR:  syntax error at or near "("

Warum, und die Lösung

Die Zeilen eines mehrzeiligen INSERT werden durch Kommas getrennt. Fehlt eines, liest PostgreSQL (1, 'Dune') zu Ende, erwartet keine weitere Klammer und hält beim ( der nächsten Zeile an. Sehen Sie sich das Ende der Zeile vor der an, auf die der Fehler zeigt, und setzen Sie dort das Komma.

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.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Drei Tabellen, jede Tatsache an einem Ort

Die Bibliothek kennt drei Arten von Tatsachen: Bücher (Titel, Autor, Jahr, Genre, Exemplare), Mitglieder (Name, E-Mail, Stadt, Beitrittstag) und Ausleihen (welches Buch an welches Mitglied ging, wann, und wann es zurückkam). Jede bekommt eine eigene Tabelle mit einer Spalte id, die ihre Zeilen nummeriert. Eine Ausleihe wiederholt weder Titel noch Namen: Sie speichert book_id und member_id, die ids des Buchs und des Mitglieds. Die Typen folgen den Daten: integer für ids, Jahre und Exemplare, text für Namen und Titel, date für Tage. Eine Spalte vom Typ date nimmt nur echte Daten an; ein Fehler wie 2026-09-31 wird also schon beim Einfügen abgelehnt, nicht erst Monate später entdeckt.

Viele Zeilen auf einmal laden, und NULL für das Unbekannte

Ein INSERT kann viele Zeilen hinzufügen: INSERT INTO books VALUES (…), (…), (…); mit einem Komma zwischen den Zeilen und einem Semikolon am Ende. Text und Daten stehen in einfachen Anführungszeichen, Daten in der eindeutigen Form '2026-09-01'. Ist ein Wert unbekannt, schreiben Sie NULL ohne Anführungszeichen: Linus hat keine E-Mail, Margaret keine Stadt, und eine offene Ausleihe hat kein Rückgabedatum. 'NULL' in Anführungszeichen sind die vier Buchstaben N, U, L, L: Eine date-Spalte lehnt sie ab, eine text-Spalte würde sie als Wort speichern. Ein INSERT ist eine Anweisung: Ist eine ihrer Zeilen falsch, wird keine hinzugefügt.

Prüfen, was Sie gebaut haben, und das Skript wiederholbar machen

Schauen Sie nach dem Laden hin: SELECT * FROM members ORDER BY id; zeigt jede Zeile in fester Reihenfolge, NULL als leere Zelle, und SELECT count(*) FROM loans; zählt die Zeilen (6 Bücher, 4 Mitglieder, 5 Ausleihen). Auf Ihrem Computer bleiben Tabellen, bis Sie sie löschen; ein zweiter Lauf des Skripts endet also bei ERROR: relation "books" already exists. Beginnen Sie das Skript darum für jede Tabelle mit DROP TABLE IF EXISTS books;: Es entfernt die alte Tabelle oder gibt, wenn es keine gibt, nur einen Hinweis aus. Speichern Sie das Skript als library.sql und führen Sie es mit psql -X -q -v ON_ERROR_STOP=1 -f library.sql aus, wann immer Sie eine frische Bibliothek wollen.

Quellen

Zuletzt geprüft am 30. September 2026