Premium

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.5
CREATE SEQUENCE sequence_name
    [START WITH startwert]
    [INCREMENT BY schrittweite]
    [MINVALUE minimalwert]
    [MAXVALUE maximalwert]
    [CYCLE | NO CYCLE]
    [CACHE anzahl];

SEQUENCE-Parameter

ParameterBeschreibungStandard
START WITHStartwert der Sequenz1
INCREMENT BYSchrittweite (kann negativ sein)1
MINVALUEMinimalwert1
MAXVALUEMaximalwert9223372036854775807
CYCLEVon vorn beginnen, wenn die Grenze erreicht wirdNO CYCLE
CACHEAnzahl der vorab reservierten Werte1

Eine SEQUENCE für Bestellnummern, beginnend bei 1000, sieht zum Beispiel so aus:

PostgreSQL 17.5
CREATE 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.5
SELECT nextval('order_id_seq');

Diese Funktion erhöht den Zähler und gibt den neuen Wert zurück. ⬆️

nextval
1000

Beim nächsten Aufruf:

PostgreSQL 17.5
SELECT nextval('order_id_seq');
nextval
1001

currval() — den aktuellen Wert abfragen

PostgreSQL 17.5
SELECT 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.5
SELECT 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.5
CREATE 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.5
INSERT INTO Orders (customer_name, order_date)
VALUES ('Iwan Petrow', '2025-11-14');
order_idcustomer_nameorder_date
1000Iwan Petrow2025-11-14

Variante 2: Typ SERIAL

PostgreSQL bietet den bequemen Typ SERIAL, der die SEQUENCE automatisch anlegt: 💡

PostgreSQL 17.5
CREATE TABLE Products (
    product_id SERIAL PRIMARY KEY,
    product_name VARCHAR(100),
    price DECIMAL(10, 2)
);

Das entspricht:

PostgreSQL 17.5
CREATE 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.5
    SELECT * FROM information_schema.sequences
    WHERE sequence_name = 'order_id_seq';
    

    Oder detaillierter über die Systemfunktion:

    PostgreSQL 17.5
    SELECT last_value, is_called FROM order_id_seq;
    
  • Parameter der SEQUENCE ändern

    PostgreSQL 17.5
    ALTER SEQUENCE order_id_seq
        INCREMENT BY 10
        RESTART WITH 2000;
    
  • SEQUENCE löschen

    PostgreSQL 17.5
    DROP 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.5
    DROP 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.5
CREATE 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

SEQUENCE: document_number_seq
100000
Invoices
DeliveryNotes
Acts

Fortgeschrittene Techniken

  • SEQUENCE mit Caching

    Für mehr Performance kannst du Caching nutzen:

    PostgreSQL 17.5
    CREATE 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.5
    CREATE 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.5
    CREATE 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! 🚀