SQL SEQUENCE in PostgreSQL: ein ID-Generator für mehrere Tabellen
Wenn du in PostgreSQL eindeutige Identifier erzeugen willst, denkt man zuerst an SERIAL. Dieser Mechanismus ist einfach zu nutzen und löst die Aufgabe in den meisten Fällen problemlos. Aber was, wenn die Aufgabe etwas komplizierter wird?
Stell dir vor: Du sollst ein Nummerierungssystem für Dokumente bauen, in dem die Nummern über mehrere Tabellen hinweg gemeinsam vergeben werden.
Rechnungen, Lieferscheine und Abnahmeprotokolle sollen beispielsweise aus einem einzigen Zahlenstrom durchnummeriert werden: 100001, 100002, 100003 … Versucht man, für jede Tabelle ein eigenes SERIAL zu nehmen, kommt es zu doppelten Nummern, und das ist nicht akzeptabel 🚫
Genau hier kommt SEQUENCE ins Spiel — ein mächtiges Werkzeug zur Erzeugung eindeutiger Identifier mit einer Flexibilität, die SERIAL nicht bieten kann.
Was ist eine SEQUENCE?
SEQUENCE ist ein spezielles Datenbankobjekt, das nach einer festgelegten Regel eine geordnete Folge eindeutiger Zahlenwerte erzeugt.
Stell dir einen automatischen Dokumenten-Nummerator im Büro vor: Jedes Mal, wenn ein neues Dokument hereinkommt, vergibt der Nummerator die nächste Nummer. SEQUENCE arbeitet genauso, nur in der Datenbank.
Ein einfaches Beispiel: Du hast einen Zähler, der bei 1000 steht. Sagst du „gib mir die nächste Zahl", liefert er 1000 und erhöht sich auf 1001. Beim nächsten Mal gibt er 1001 zurück, dann 1002, und so weiter. Schlicht und zuverlässig! ✨
Wozu braucht man SEQUENCE?
SEQUENCE gibt dir deutlich mehr Kontrolle und Flexibilität als SERIAL. Die wichtigsten Vorteile:
-
🔗 Unabhängig von Tabellen
Eine SEQUENCE kann gleichzeitig IDs für mehrere Tabellen liefern. Rechnungen, Lieferscheine und Abnahmeprotokolle lassen sich so aus einem einzigen Zahlenstrom durchnummerieren — das garantiert eindeutige Dokumentnummern im gesamten System. -
🎨 Flexibel konfigurierbar
Du kannst bei einer beliebigen Zahl starten (z. B. 1000), rückwärts zählen, eine zyklische Nummerierung einrichten oder die Schrittweite ändern.
Eine SEQUENCE anlegen
SEQUENCE wird mit dem Befehl CREATE SEQUENCE angelegt.
Basis-Syntax
PostgreSQL 17.5CREATE SEQUENCE sequence_name [START WITH startwert] [INCREMENT BY schrittweite] [MINVALUE minimalwert] [MAXVALUE maximalwert] [CYCLE | NO CYCLE] [CACHE anzahl];
SEQUENCE-Parameter
Eine SEQUENCE für Bestellnummern, beginnend bei 1000, sieht zum Beispiel so aus:
PostgreSQL 17.5CREATE SEQUENCE order_id_seq START WITH 1000 INCREMENT BY 1 NO CYCLE;
Funktionen für die Arbeit mit SEQUENCE
PostgreSQL bietet mehrere Funktionen rund um SEQUENCE:
nextval() — den nächsten Wert holen
PostgreSQL 17.5SELECT nextval('order_id_seq');
Diese Funktion erhöht den Zähler und gibt den neuen Wert zurück. ⬆️
Beim nächsten Aufruf:
PostgreSQL 17.5SELECT nextval('order_id_seq');
currval() — den aktuellen Wert abfragen
PostgreSQL 17.5SELECT currval('order_id_seq');
Gibt den letzten Wert zurück, der per nextval() in der aktuellen Session geholt wurde, ohne den Zähler zu verändern. 👀
⚠️ Wichtige Falle! Beim ersten Einsatz von currval() kann der Fehler „currval of sequence is not yet defined in this session" auftreten. Ursache: currval() lässt sich erst aufrufen, nachdem in derselben Session mindestens einmal nextval() aufgerufen wurde!
Die Logik ist simpel: man kann den „aktuellen" Wert nicht kennen, wenn er in der laufenden Session noch nie angefordert wurde. 🤔
setval() — einen Wert setzen
PostgreSQL 17.5SELECT setval('order_id_seq', 5000);
Setzt den aktuellen Wert der SEQUENCE. Der nächste nextval()-Aufruf liefert 5001. 🎯
Einsatz in Tabellen
Variante 1: DEFAULT nutzen
Der häufigste Weg: SEQUENCE als Default-Wert nutzen:
PostgreSQL 17.5CREATE TABLE Orders ( order_id INTEGER DEFAULT nextval('order_id_seq') PRIMARY KEY, customer_name VARCHAR(100), order_date DATE );
Beim Einfügen einer Zeile wird order_id automatisch befüllt:
PostgreSQL 17.5INSERT INTO Orders (customer_name, order_date) VALUES ('Iwan Petrow', '2025-11-14');
Variante 2: Typ SERIAL
PostgreSQL bietet den bequemen Typ SERIAL, der die SEQUENCE automatisch anlegt: 💡
PostgreSQL 17.5CREATE TABLE Products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(100), price DECIMAL(10, 2) );
Das entspricht:
PostgreSQL 17.5CREATE SEQUENCE products_product_id_seq; CREATE TABLE Products ( product_id INTEGER DEFAULT nextval('products_product_id_seq') PRIMARY KEY, product_name VARCHAR(100), price DECIMAL(10, 2) );
SEQUENCE verwalten
-
Informationen zur SEQUENCE ansehen
PostgreSQL 17.5SELECT * FROM information_schema.sequences WHERE sequence_name = 'order_id_seq';Oder detaillierter über die Systemfunktion:
PostgreSQL 17.5SELECT last_value, is_called FROM order_id_seq; -
Parameter der SEQUENCE ändern
PostgreSQL 17.5ALTER SEQUENCE order_id_seq INCREMENT BY 10 RESTART WITH 2000; -
SEQUENCE löschen
PostgreSQL 17.5DROP SEQUENCE order_id_seq;⚠️ Achtung: Wird die SEQUENCE in einer Tabelle als Default-Wert genutzt, musst du diese Bindung zuerst entfernen oder CASCADE verwenden:
PostgreSQL 17.5DROP SEQUENCE order_id_seq CASCADE;
SEQUENCE für mehrere Tabellen
Eine SEQUENCE kann für mehrere Tabellen verwendet werden. Besonders nützlich für Dokumentenverwaltungssysteme mit übergreifender Nummerierung:
PostgreSQL 17.5CREATE SEQUENCE document_number_seq START WITH 100000; CREATE TABLE Invoices ( invoice_id SERIAL PRIMARY KEY, document_number INTEGER DEFAULT nextval('document_number_seq') UNIQUE, customer_id INTEGER, amount DECIMAL(10, 2) ); CREATE TABLE DeliveryNotes ( note_id SERIAL PRIMARY KEY, document_number INTEGER DEFAULT nextval('document_number_seq') UNIQUE, order_id INTEGER, delivery_date DATE ); CREATE TABLE Acts ( act_id SERIAL PRIMARY KEY, document_number INTEGER DEFAULT nextval('document_number_seq') UNIQUE, contract_id INTEGER, act_date DATE );
Jetzt haben alle Dokumente (Rechnungen, Lieferscheine, Abnahmeprotokolle) eindeutige Nummern im gesamten Dokumentenfluss. 🌐
Interaktives SEQUENCE-Diagramm
Fortgeschrittene Techniken
-
SEQUENCE mit Caching
Für mehr Performance kannst du Caching nutzen:
PostgreSQL 17.5CREATE SEQUENCE fast_seq START WITH 1 INCREMENT BY 1 CACHE 100;Die Datenbank reserviert 100 Werte im Voraus im Speicher, was die Ausgabe beschleunigt. ⚡
-
Zyklische SEQUENCE
Für Fälle, in denen eine zyklische Nummerierung gebraucht wird (etwa Wochentage):
PostgreSQL 17.5CREATE SEQUENCE day_of_week_seq START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 7 CYCLE;Nach Erreichen der 7 kehrt die SEQUENCE zur 1 zurück. 🔄
-
Absteigende SEQUENCE
PostgreSQL 17.5CREATE SEQUENCE countdown_seq START WITH 100 INCREMENT BY -1 MINVALUE 1 NO CYCLE;Diese SEQUENCE produziert: 100, 99, 98, 97 … ⬇️
Worauf du achten solltest
-
In 90 % der Fälle reicht SERIAL
Leg keine eigene SEQUENCE an, wenn du ihre spezielle Flexibilität nicht brauchst. SERIAL ist einfacher und löst die meisten Aufgaben. -
Sequenzen haben Lücken 🕳️
Erwarte nicht, dass die Nummern lückenlos durchlaufen: 1, 2, 3, 4 … Transaktions-Rollbacks, parallele Anfragen, Caching — all das erzeugt Lücken. Wenn du „Bestellung Nr. 102 nach Nr. 99" siehst — das ist normal.Brauchst du wirklich eine durchgehende Nummerierung (etwa für Rechnungen wegen buchhalterischer Anforderungen), ist SEQUENCE nicht die beste Wahl.
-
Ein vergessener MAXVALUE ist eine Zeitbombe 💥
MAXVALUE 999999 gesetzt und vergessen? Nach dem millionsten Eintrag steht alles still. Im Produktivbetrieb nimm immer den maximal möglichen Wert oder überwache die Annäherung an die Grenze.
Zusammengefasst
Für die meisten Aufgaben tut SERIAL seinen Dienst hervorragend. Brauchst du aber eine gemeinsame Nummerierung über mehrere Tabellen, eine spezielle Schrittweite oder die Möglichkeit, eine ID vor dem Insert zu bekommen — dann löst SEQUENCE diese Aufgaben elegant.
Hauptsache: vergiss die Lücken in der Nummerierung nicht und behalte MAXVALUE im Auge. Sonst ist es ein einfaches und mächtiges Werkzeug! 🚀