Aufwärmen · Aufgabe 1 von 7
// B4.2 · ca. 30 Min. · Einstieg
RETURNING: die Zeilen, die Sie gerade geändert haben
Nach dieser Lektion holen Sie die id einer neuen Zeile direkt aus ihrem INSERT, sehen, was ein UPDATE oder DELETE geändert hat, und zeigen alte und neue Werte nebeneinander.
Danach können Sie
- Die von INSERT, UPDATE und DELETE geänderten Zeilen mit RETURNING zurückholen, auch eine erzeugte id
- Vorhersagen, was RETURNING standardmäßig zeigt: die eingefügte Zeile, die neuen Werte, die gelöschte Zeile
- Alte und neue Werte mit old. und new. aus PostgreSQL 18 nebeneinander zeigen und sie mit WITH umbenennen
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es voraus, bevor Sie weiterlesen. Dune hat 2 Exemplare, The Hobbit 3, jedes andere Buch 1. Welche title und copies gibt das UPDATE zurück?
UPDATE books SET copies = copies - 1 WHERE copies > 1 RETURNING title, copiesÜben · Aufgabe 3 von 7
Die Ausleihen haben die ids 1 bis 5. Ergänzen Sie die Spalte, damit das INSERT die Nummer zurückgibt, die PostgreSQL der neuen Ausleihe gibt.
INSERT INTO loans (book_id, member_id, loaned_on) VALUES (4, 4, '2026-10-03') RETURNING ____;INSERT INTO loans (book_id, member_id, loaned_on) VALUES (4, 4, '2026-10-03') RETURNING ;Üben · Aufgabe 4 von 7
Ordnen Sie jedem RETURNING zu, was es zeigt.
Üben · Aufgabe 5 von 7
Bringen Sie die Teile der Anweisung in die richtige Reihenfolge.
- 1.SET copies = copies + 1
- 2.WHERE genre = 'sci-fi'
- 3.RETURNING title, old.copies, new.copies;
- 4.UPDATE books
Denksport · Aufgabe 6 von 7
Knobelaufgabe. Drei Bücher sind sci-fi. SET lässt jeden Wert, wie er war. Wie viele Zeilen gibt das zurück?
UPDATE books SET copies = copies WHERE genre = 'sci-fi' RETURNING titleAnwenden · Aufgabe 7 von 7
Mini-Aufgabe. Mit der Bibliothek aus dem durchgerechneten Beispiel: Hedy (hedy@example.com, aus Wien, in den Daten Vienna) tritt am 2026-10-03 bei. Legen Sie sie mit einem INSERT an, das ihre neue id zurückgibt. Halten Sie mit dieser id ihre Ausleihe von The Hobbit (Buch 5) am selben Tag fest und geben Sie wieder die id der neuen Ausleihe zurück. Dann kauft die Bibliothek ein Exemplar mehr von jedem fantasy-Buch: Geben Sie jeden Titel mit seinen Exemplaren vorher und nachher zurück.
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
Geänderte Zeilen zurückbekommen
setup.sql lädt die Bibliothek aus Modul B1; hier nummeriert PostgreSQL die Mitglieder und Ausleihen selbst. main.sql legt eine Ausleihe an und bekommt ihre id zurück, markiert eine Ausleihe als zurückgegeben, fügt jedem sci-fi-Buch ein Exemplar hinzu, mit den Werten vorher und nachher, und löscht ein Mitglied, wobei es die gelöschte Zeile zeigt. Auf Ihrem Computer: psql -X -q -v ON_ERROR_STOP=1 -f setup.sql -f main.sql.
main.sql
-- 1. A new loan: PostgreSQL picks the id, RETURNING shows it.
INSERT INTO loans (book_id, member_id, loaned_on)
VALUES (4, 4, '2026-10-03')
RETURNING id, book_id, loaned_on;
-- 2. Kindred comes back: RETURNING shows the row after the update.
UPDATE loans
SET returned_on = '2026-10-03'
WHERE id = 2
RETURNING id, loaned_on, returned_on;
-- 3. PostgreSQL 18: the old and the new value side by side.
UPDATE books
SET copies = copies + 1
WHERE genre = 'sci-fi'
RETURNING title, old.copies AS before, new.copies AS after;
-- 4. A deleted row, shown one last time.
DELETE FROM members
WHERE name = 'Margaret'
RETURNING *;
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);
-- PostgreSQL numbers the members and the loans itself (lesson B4.4).
CREATE TABLE members (
id integer GENERATED ALWAYS AS IDENTITY,
name text,
email text,
city text,
joined date
);
INSERT INTO members (name, email, city, joined) VALUES
('Ada', 'ada@example.com', 'Berlin', '2025-01-15'),
('Grace', 'grace@example.com', 'Munich', '2025-03-02'),
('Linus', NULL, 'Berlin', '2026-02-10'),
('Margaret', 'margaret@example.com', NULL, '2026-05-20');
CREATE TABLE loans (
id integer GENERATED ALWAYS AS IDENTITY,
book_id integer,
member_id integer,
loaned_on date,
returned_on date
);
INSERT INTO loans (book_id, member_id, loaned_on, returned_on) VALUES
(1, 1, '2026-09-01', '2026-09-10'),
(3, 1, '2026-09-12', NULL),
(2, 2, '2026-09-05', '2026-09-20'),
(1, 3, '2026-09-15', NULL),
(6, 2, '2026-09-18', NULL);
Ausführen mit
psql -X -q -v ON_ERROR_STOP=1 -f setup.sql -f main.sqlAusgabe
id | book_id | loaned_on
----+---------+------------
6 | 4 | 2026-10-03
(1 row)
id | loaned_on | returned_on
----+------------+-------------
2 | 2026-09-12 | 2026-10-03
(1 row)
title | before | after
-------------+--------+-------
Dune | 2 | 3
Kindred | 1 | 2
Neuromancer | 1 | 2
(3 rows)
id | name | email | city | joined
----+----------+----------------------+------+------------
4 | Margaret | margaret@example.com | | 2026-05-20
(1 row)- Das INSERT hat keine id angegeben; PostgreSQL hat 6 gewählt, die nächste Nummer, und RETURNING zeigt sie.
- returned_on ist schon das neue Datum: Das RETURNING eines UPDATE zeigt die Zeile nach der Änderung.
- old.copies und new.copies zeigen jedes sci-fi-Buch vor und nach dem UPDATE, in einer Anweisung.
- Das DELETE gibt Margarets Zeile zurück, wie sie war; ihre leere Stadt ist NULL.
Ä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
Die neuen ids zurückbekommen
Hedy (hedy@example.com, aus Wien, in den Daten Vienna) tritt der Bibliothek am 2026-10-03 bei. Der Startcode legt sie an, gibt aber nichts zurück. Lassen Sie das INSERT ihre id und ihren Namen zurückgeben. Legen Sie dann ihre Ausleihe von The Hobbit (Buch 5) am 2026-10-03 an, mit der id aus der ersten Anweisung als member_id, und geben Sie id, book_id und member_id der Ausleihe zurück.
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
RETURNING steht ganz am Ende des INSERT, nach der VALUES-Liste.
Hinweis 2
Die erste Anweisung gibt 5 zurück; verwenden Sie das als member_id in der Ausleihe.
Hinweis 3
INSERT INTO loans (book_id, member_id, loaned_on) VALUES (5, 5, '2026-10-03') RETURNING id, book_id, member_id;
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
INSERT INTO members (name, email, city, joined)
VALUES ('Hedy', 'hedy@example.com', 'Vienna', '2026-10-03')
RETURNING id, name;
INSERT INTO loans (book_id, member_id, loaned_on)
VALUES (5, 5, '2026-10-03')
RETURNING id, book_id, member_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.
INSERT INTO members (name, email, city, joined)
VALUES ('Hedy', 'hedy@example.com', 'Vienna', '2026-10-03');
test.sql
-- test: Hedy ist ein Mitglied aus Wien (Vienna), von PostgreSQL mit 5 nummeriert
SELECT EXISTS (SELECT 1 FROM members WHERE id = 5 AND name = 'Hedy' AND city = 'Vienna');
-- test: Ihre offene Ausleihe von The Hobbit ist Ausleihe 6
SELECT EXISTS (SELECT 1 FROM loans WHERE id = 6 AND book_id = 5 AND member_id = 5 AND loaned_on = '2026-10-03' AND returned_on IS NULL);
-- test: Beide Anweisungen geben die neuen Zeilen zurück
-- output:
-- id | name
-- ----+------
-- 5 | Hedy
-- (1 row)
--
-- id | book_id | member_id
-- ----+---------+-----------
-- 6 | 5 | 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);
-- PostgreSQL numbers the members and the loans itself (lesson B4.4).
CREATE TABLE members (
id integer GENERATED ALWAYS AS IDENTITY,
name text,
email text,
city text,
joined date
);
INSERT INTO members (name, email, city, joined) VALUES
('Ada', 'ada@example.com', 'Berlin', '2025-01-15'),
('Grace', 'grace@example.com', 'Munich', '2025-03-02'),
('Linus', NULL, 'Berlin', '2026-02-10'),
('Margaret', 'margaret@example.com', NULL, '2026-05-20');
CREATE TABLE loans (
id integer GENERATED ALWAYS AS IDENTITY,
book_id integer,
member_id integer,
loaned_on date,
returned_on date
);
INSERT INTO loans (book_id, member_id, loaned_on, returned_on) VALUES
(1, 1, '2026-09-01', '2026-09-10'),
(3, 1, '2026-09-12', NULL),
(2, 2, '2026-09-05', '2026-09-20'),
(1, 3, '2026-09-15', NULL),
(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
Vorher und nachher
Die Bibliothek verdoppelt jedes Buch, von dem es nur ein Exemplar gibt. Der Startcode macht das, gibt aber nur die neuen copies zurück. Lassen Sie es title, die copies vorher als before und nachher als after zurückgeben. Löschen Sie dann jede zurückgegebene Ausleihe (returned_on ist nicht NULL) und geben Sie id und book_id jeder gelöschten Ausleihe zurück.
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
Bei einem UPDATE ist ein einfaches copies in RETURNING der neue Wert. old.copies ist der Wert vorher.
Hinweis 2
Benennen Sie die Spalten mit AS: old.copies AS before, new.copies AS after.
Hinweis 3
DELETE FROM loans WHERE returned_on IS NOT NULL RETURNING id, book_id;
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
UPDATE books
SET copies = copies * 2
WHERE copies = 1
RETURNING title, old.copies AS before, new.copies AS after;
DELETE FROM loans
WHERE returned_on IS NOT NULL
RETURNING id, book_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
-- Double the copies of every book with one copy.
UPDATE books
SET copies = copies * 2
WHERE copies = 1
RETURNING title, copies;
test.sql
-- test: Die Bücher haben jetzt insgesamt 13 Exemplare
SELECT sum(copies) = 13 FROM books;
-- test: Nur die drei offenen Ausleihen bleiben
SELECT count(*) = 3 AND count(returned_on) = 0 FROM loans;
-- test: Das UPDATE zeigt vorher und nachher, das DELETE die gelöschten Ausleihen
-- output:
-- title | before | after
-- -------------+--------+-------
-- Emma | 1 | 2
-- Kindred | 1 | 2
-- Beloved | 1 | 2
-- Neuromancer | 1 | 2
-- (4 rows)
--
-- id | book_id
-- ----+---------
-- 1 | 1
-- 3 | 2
-- (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);
-- PostgreSQL numbers the members and the loans itself (lesson B4.4).
CREATE TABLE members (
id integer GENERATED ALWAYS AS IDENTITY,
name text,
email text,
city text,
joined date
);
INSERT INTO members (name, email, city, joined) VALUES
('Ada', 'ada@example.com', 'Berlin', '2025-01-15'),
('Grace', 'grace@example.com', 'Munich', '2025-03-02'),
('Linus', NULL, 'Berlin', '2026-02-10'),
('Margaret', 'margaret@example.com', NULL, '2026-05-20');
CREATE TABLE loans (
id integer GENERATED ALWAYS AS IDENTITY,
book_id integer,
member_id integer,
loaned_on date,
returned_on date
);
INSERT INTO loans (book_id, member_id, loaned_on, returned_on) VALUES
(1, 1, '2026-09-01', '2026-09-10'),
(3, 1, '2026-09-12', NULL),
(2, 2, '2026-09-05', '2026-09-20'),
(1, 3, '2026-09-15', NULL),
(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
RETURNING vor WHERE
UPDATE loans
SET returned_on = '2026-10-03'
RETURNING *
WHERE id = 2;
Was psql ausgibt
ERROR: syntax error at or near "WHERE"Warum, und die Lösung
RETURNING ist die letzte Klausel der Anweisung. PostgreSQL liest RETURNING * als Ende des UPDATE und erwartet danach kein WHERE. Ziehen Sie WHERE nach oben: UPDATE loans SET returned_on = '2026-10-03' WHERE id = 2 RETURNING *. Dasselbe gilt für DELETE … WHERE … RETURNING.
Einer GENERATED-ALWAYS-id einen Wert geben
INSERT INTO members (id, name, email)
VALUES (5, 'Hedy', 'hedy@example.com')
RETURNING id;
Was psql ausgibt
ERROR: cannot insert a non-DEFAULT value into column "id"Warum, und die Lösung
members.id ist GENERATED ALWAYS AS IDENTITY: PostgreSQL wählt jede id selbst und lehnt eine ab, die Sie angeben. Lassen Sie id aus der Spaltenliste weg und lassen Sie sich von RETURNING id sagen, welche Nummer die Zeile bekommen hat. psql ergänzt einen HINT zu OVERRIDING SYSTEM VALUE; das ist zum Kopieren vorhandener Daten gedacht, nicht für alltägliche Inserts.
old. nach dem Umbenennen
UPDATE books
SET copies = copies + 1
WHERE id = 5
RETURNING WITH (OLD AS o, NEW AS n) old.copies, n.copies;
Was psql ausgibt
ERROR: missing FROM-clause entry for table "old"Warum, und die Lösung
WITH (OLD AS o, NEW AS n) gibt der alten und der neuen Zeile andere Namen, und dann sind die Namen old und new in dieser RETURNING-Liste verdeckt. Verwenden Sie durchgehend die neuen Namen: RETURNING WITH (OLD AS o, NEW AS n) o.copies, n.copies. Ohne den WITH-Teil funktionieren old.copies und new.copies so, wie sie sind.
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.