Heute schauen wir uns an, wie man eine echte Prozedur zur Bearbeitung von Bestellungen aufbaut. Sie besteht aus mehreren Schritten: Datenvalidierung, Status-Update der Bestellung und Logging. Stell dir ein Restaurant vor, wo der Chefkoch, der Kellner und der Kassierer zusammenarbeiten müssen. In unserer Prozedur setzen wir eine ähnliche Logik für die Zusammenarbeit zwischen den Schritten um.
Beschreibung der Aufgabenstellung
Die Prozedur zur Bestellbearbeitung soll folgende Schritte ausführen:
- Prüfen, ob das gewünschte Produkt auf Lager ist.
- Wenn genug da ist, die Menge vom Lager abziehen.
- Status der Bestellung auf "Bearbeitet" setzen.
- Info über die erfolgreiche Operation ins Log schreiben.
- Bei jedem Fehler alles auf Anfang zurücksetzen (Rollback).
Implementierung der Prozedur
Schritt 1. Schema und Tabellen anlegen
Bevor wir die Prozedur schreiben, legen wir die Tabellen an, mit denen sie arbeitet.
Tabelle orders — Bestellungen
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_name TEXT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0),
status TEXT DEFAULT 'Pending'
);
Diese Tabelle speichert die Bestellungen. Jede Bestellung hat einen Kunden, eine Produkt-ID, eine Menge und einen Status (standardmäßig "Wartet auf Bearbeitung").
Tabelle inventory — Lager
CREATE TABLE inventory (
product_id SERIAL PRIMARY KEY,
product_name TEXT NOT NULL UNIQUE,
stock INT NOT NULL CHECK (stock >= 0)
);
Tabelle mit der Liste der Produkte im Lager. Jedes Produkt hat einen aktuellen Bestand (stock).
Tabelle order_logs — Logbuch
CREATE TABLE order_logs (
log_id SERIAL PRIMARY KEY,
order_id INT NOT NULL REFERENCES orders(order_id) ON DELETE CASCADE,
log_message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Das Logbuch wird genutzt, um Infos über den Status der Bestellbearbeitung zu speichern.
Schritt 2. Struktur der Prozedur
So sieht die Struktur der mehrstufigen Prozedur aus:
- Prüfen, ob das gewünschte Produkt im Lager ist und ob genug davon da ist.
- Wenn genug da ist, die Menge in der Tabelle
inventoryverringern. - Status der Bestellung auf "Bearbeitet" setzen.
- Erfolgreiches Ergebnis in die Tabelle
order_logsschreiben. - Mögliche Fehler mit Rollback behandeln.
Schritt 3. Prozedur schreiben
Lass uns die Prozedur process_order für die oben beschriebenen Schritte schreiben.
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS VOID AS $$
DECLARE
v_product_id INT;
v_quantity INT;
v_stock INT;
BEGIN
-- Schritt 1: Bestellinfos holen
SELECT product_id, quantity
INTO v_product_id, v_quantity
FROM orders
WHERE order_id = $1;
-- Prüfen, ob die Bestellung existiert
IF NOT FOUND THEN
RAISE EXCEPTION 'Bestellung mit ID % existiert nicht.', $1;
END IF;
-- Schritt 2: Prüfen, ob das Produkt im Lager ist
SELECT stock INTO v_stock
FROM inventory
WHERE product_id = v_product_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Produkt mit ID % existiert nicht im Lager.', v_product_id;
END IF;
IF v_stock < v_quantity THEN
RAISE EXCEPTION 'Nicht genug Bestand für Produkt ID %. Angefragt: %, Verfügbar: %.',
v_product_id, v_quantity, v_stock;
END IF;
-- Schritt 3: Produktmenge im Lager verringern
UPDATE inventory
SET stock = stock - v_quantity
WHERE product_id = v_product_id;
-- Schritt 4: Bestellstatus auf 'Processed' setzen
UPDATE orders
SET status = 'Processed'
WHERE order_id = $1;
-- Schritt 5: Erfolg ins Log schreiben
INSERT INTO order_logs (order_id, log_message)
VALUES ($1, 'Bestellung erfolgreich bearbeitet.');
EXCEPTION
WHEN OTHERS THEN
-- Fehler ins Log schreiben, falls was schiefgeht
INSERT INTO order_logs (order_id, log_message)
VALUES ($1, 'Fehler bei der Bearbeitung der Bestellung: ' || SQLERRM);
-- Alles zurückrollen
RAISE;
END;
$$ LANGUAGE plpgsql;
Schauen wir uns die Prozedur im Detail an.
Prüfschritt:
Wir prüfen, ob die angegebene Bestellung in der Tabelle
ordersexistiert. Wenn nicht, wird eine Exception mit einer genauen Nachricht geworfen. Genauso prüfen wir, ob das Produkt im Lager ist und wie viel davon da ist.Lager-Schritt:
Wenn genug da ist, verringern wir die Menge im Lager. Das passiert mit
UPDATE.Status-Update-Schritt:
Wir setzen den Status auf "Processed" (Bearbeitet), um zu zeigen, dass die Bestellung erfolgreich abgeschlossen wurde.
Logging-Schritt:
Nach erfolgreicher Bearbeitung der Bestellung fügen wir eine Nachricht in die Tabelle
order_logsein, um die Aktion zu dokumentieren.Exception-Handling:
Wenn etwas schiefgeht, fangen wir den Fehler im
EXCEPTION-Block ab, schreiben eine genaue Fehlermeldung ins Log und rollen alle Änderungen zurück.
Beispiele zur Nutzung
Wir legen Testdaten an, um unsere Prozedur zu testen.
-- Produkt ins Lager legen
INSERT INTO inventory (product_name, stock)
VALUES ('Laptop', 10), ('Monitor', 5);
-- Bestellungen anlegen
INSERT INTO orders (customer_name, product_id, quantity)
VALUES
('Alice', 1, 2),
('Bob', 2, 1),
('Charlie', 1, 20); -- Diese Bestellung soll einen Fehler auslösen
Jetzt testen wir die Prozedur:
-- Bestellung von Alice bearbeiten
SELECT process_order(1);
-- Bestellung von Bob bearbeiten
SELECT process_order(2);
-- Versuch, Bestellung von Charlie zu bearbeiten (Fehler)
SELECT process_order(3);
Ergebnisse:
- Die Bestellungen von Alice und Bob werden erfolgreich bearbeitet, ins Log geschrieben und der Lagerbestand wird reduziert.
- Die Bestellung von Charlie löst einen Fehler aus, weil nicht genug auf Lager ist, und der Fehler wird im Log festgehalten.
Schauen wir uns die Tabellen nach den Abfragen an:
SELECT * FROM inventory; -- Änderungen im Bestand
SELECT * FROM orders; -- Änderungen im Bestellstatus
SELECT * FROM order_logs; -- Logeinträge
Typische Fehler und Tipps
Fehler:
NOT FOUNDnachSELECT INTOvergessen.Behandle immer den Fall, dass eine Abfrage kein Ergebnis liefert, sonst gibt's unerwartete Exceptions.
Fehler:
EXCEPTION-Block fehlt.Wenn du keinen Fehler-Handler hast, kann eine Exception die Transaktion blockieren oder die Logik kaputt machen.
Tipp: Schütze dich vor SQL-Injections.
Nutze strikt typisierte Parameter und vermeide dynamisches SQL, wenn es nicht nötig ist.
Prozedur erweitern
Im echten Leben kann man noch mehr Checks einbauen, zum Beispiel:
- Rabatte oder Aktionen für Kunden berücksichtigen.
- Kreditlimit des Kunden vor der Bearbeitung prüfen.
- Nicht nur erfolgreiche Aktionen, sondern auch Rollbacks loggen.
GO TO FULL VERSION