NEXTVAL-Funktion in PostgreSQL

Bilal Shahid 20 Juni 2023
NEXTVAL-Funktion in PostgreSQL

NEXTVAL() neigt dazu, ein Objekt auf einen anderen Wert zu bringen und ihn zurückzugeben. SEQUENCE OBJECTS sind nur einzeilige Tabellen, die aus SEQUENCES in PostgreSQL erstellt wurden.

Die Funktion NEXTVAL() wird unter SEQUENCE MANIPULATION FUNCTIONS definiert.

nextval ( regclass ) ? bigint

REGCLASS bezieht sich auf das SEQUENCE OBJECT, und diese Funktion neigt dazu, BIGINT zurückzugeben. Sehen wir uns nun einige mögliche Implementierungen dieser NEXTVAL()-Funktion an und wie wir sie verwenden können.

Praktisches Beispiel für NEXTVAL() in PostgreSQL

Eine der Verwendungen von SEQUENCE IDENTIFIERS in PostgreSQL besteht darin, wie sie verwendet werden können, um eindeutige Zeilenidentifizierungswerte zu erhalten. Sie können mehr darüber unter der CREATE SEQUENCE URL lesen.

Wir werden der oben angegebenen Verwendung nachgehen und dann versuchen, ein System zu implementieren, das die Funktion NEXTVAL() effektiv verwenden kann. Wir booten PostgreSQL und erstellen eine einfache Tabelle namens RANDOM_GEN (kurz für Zufallsgenerator).

CREATE TABLE RANDOM_GENE(
	val INT PRIMARY KEY
);

Wir haben einen einfachen VALUE als PRIMARY KEY in unserer Tabelle verwendet, da er einzigartig und zufällig ist. Lassen Sie uns nun fortfahren und einige Daten an diese Tabelle anhängen.

Natürlich sollte das VAL RANDOM sein, um den SEQUENCE GENERATOR in PostgreSQL zu verwenden. Unser Tutorial verwendet einen SERIAL GENERATOR mit inkrementierenden Werten, um UNIQUE VAL zu erhalten.

CREATE SEQUENCE serial_num;

Und um die Werte aus diesem SEQUENCE GENERATOR zu verwenden, können wir eine SELECT-Operation aus dieser Tabelle abfragen.

SELECT * from SERIAL_NUM;

Aber es gibt ein Problem. Wenn wir diese SELECT-Operation wiederholt aufrufen, erhalten wir tendenziell denselben Wert vom SEQUENCE GENERATOR.

Wenn wir also ohne Test Werte aus dieser SEQUENCE in unsere Tabelle INSERT hätten, hätten wir am Ende doppelte Werte erhalten.

Und hier kommt die Funktion NEXTVAL() ins Spiel. Wir können fortfahren und den Wert dieses GENERATOR erhöhen und dann die Operation SELECT ausführen, um die aufsteigenden Werte zu erhalten.

Wir können also schreiben:

SELECT * from NEXTVAL('serial_num');

Und dies gibt die Ausgabe wie folgt für, sagen wir, 5 Iterationen zurück.

Ausgang:

Iter      VAL
1          1
2          2
3          3
4          4
5          5

Also tendiert NEXTVAL(), wie wir gesehen haben, dazu, den SEQUENCE GENERATOR zu erhöhen und vorzurücken. Jedes Mal, wenn NEXTVAL() für die in seinem Argument übergebene SEQUENCE aufgerufen wird, können wir uns vorstellen, dass die SEQUENCE auf den nächsten aufsteigenden Wert zeigt.

Daher können wir jetzt etwas wie folgt für eine INSERT-Operation in unsere RANDOM_GEN-Tabelle aufrufen.

INSERT INTO RANDOM_GENE values (NEXTVAL('SERIAL_NUM')), (NEXTVAL('SERIAL_NUM')), (NEXTVAL('SERIAL_NUM'));

Unsere Tabelle sieht nun wie folgt aus.

Ausgang:

        val
1       1
2       2
3       3

Eine andere einfache Möglichkeit, dies nur für die Spalte VALUE zu erreichen, wäre, NEXTVAL() direkt in der Anweisung CREATE TABLE zu definieren. Wir können eine Abfrage wie folgt schreiben.

CREATE TABLE RANDOM_GENE(
	val INT primary key default NEXTVAL('SERIAL_NUM')
);

Wir haben DEFAULT verwendet, um das Standardverhalten dieser VAL-Spalte zu definieren, die Werte vom SEQUENCE GENERATOR erhält. Natürlich ist das Obige ohne eine sekundäre Spalte nutzlos, also fügen wir eine Spalte USER_NAME hinzu, um die USERS zu definieren, die die RANDOM_GEN-Werte erhalten.

CREATE TABLE RANDOM_GENE(
	val INT primary key default NEXTVAL('SERIAL_NUM'),
        name TEXT
);

Wir können nun eine INSERT-Anweisung wie folgt schreiben.

INSERT into RANDOM_GENE (name) values ('John'), ('Marta'), ('Alex');

Dadurch werden die in der Abfrage angegebenen Namen in unsere Tabelle mit den entsprechenden Werten, die in aufsteigender Reihenfolge von unserem SEQUENCE GENERATOR erhalten wurden, INSERT. Wenn wir jetzt eher auf die Tabelle schauen, wäre es wie folgt.

val     name
1	"John"
2	"Marta"
3	"Alex"

Daher haben wir jetzt vollständig verstanden, wie NEXTVAL() funktioniert. Betrachten wir zunächst die Funktionsweise von NEXTVAL() in verschiedenen Umgebungen.

NEXTVAL() in verschiedenen Umgebungen und Umständen in PostgreSQL

Die Verwendung von NEXTVAL() neigt dazu, den SEQUENCE GENERATOR bei jedem Aufruf zu erhöhen. Daher müssen wir uns in diesem Fall keine Gedanken über Duplikate machen.

Sobald NEXTVAL() aufgerufen wird, wird der GENERATOR weitergeschaltet und berechnet den nächsten Wert. Jede andere gleichzeitig laufende Abfrage, die NEXTVAL() für dieselbe SEQUENCE aufruft, erhält den völlig anderen und eindeutigen Wert des Generators.

Daher ist es effizient und sicher, NEXTVAL() für mehrere Transaktionen und Prozesse zu verwenden, die möglicherweise Abfragen auf einem Postgres-Server ausführen.

Lücken und Wertunterschiede von NEXTVAL() in PostgreSQL

Ein häufiges Problem in NEXTVAL() ist die strikte Implementierung der Weiterentwicklung. Sobald die SEQUENCE zu den neuen Werten vorrückt, ist es höchst unwahrscheinlich, dass sie zurückkehrt oder sogar überprüft, ob ein vorheriger Wert verwendet wurde oder nicht.

Falls Sie also eine Tabelle mit einer UNIQUE-Wertspalte und einem NAME haben und der NAME, den Sie INSERT eingeben möchten, irgendwie bereits in der Tabelle vorhanden ist, können Sie einen Verletzungsfehler erhalten. NEXTVAL() wäre in diesem Szenario bereits aufgerufen worden.

Und die SEQUENCE ist auf einen Wert vorgerückt, aber die Verletzung verhindert die INSERTION. Beim nächsten Aufruf von INSERT rückt NEXTVAL() also wieder vor und der vorherige Wert wird komplett übersprungen.

Dasselbe gilt für ON CONFLICT-Operationen oder solche, die möglicherweise nicht richtig ausgeführt werden. Verwenden Sie im folgenden Beispiel den folgenden Befehl, um ein INSERT auf die Tabellenspalte NAME aufzurufen.

name TEXT unique

Und dann INSERTen wir Daten in unsere Tabelle mit einem absichtlich doppelten Namen für ALEX mit einer Abfrage wie folgt.

INSERT into RANDOM_GENE (name) values ('John'), ('Marta'), ('Alex'), ('Alex'), ('Mathew') on conflict (name) do nothing;

Wir haben ON CONFLICT gesetzt, um den doppelten Verletzungsfehler zu umgehen und unsere Tabelle auf VALUE zu überprüfen. Die Tabelle sieht nun wie folgt aus.

val    name
1	"John"
2	"Marta"
3	"Alex"
5	"Mathew"

Sie können sehen, dass es keinen 4-Wert für die Spalte VAL gibt. Und das liegt daran, dass die doppelte ALEX-Einfügung den SEQUENCE GENERATOR vorrückte, aber nicht INSERTED wurde.

So lag für den Namen MATHEW der Wert bereits bei 4, der dann für dessen INSERTION auf 5 vorrückte.

Nun hoffen wir, dass Sie die Funktionsweise von NEXTVAL() vollständig verstanden haben und nach Belieben umsetzen können.

Bilal Shahid avatar Bilal Shahid avatar

Hello, I am Bilal, a research enthusiast who tends to break and make code from scratch. I dwell deep into the latest issues faced by the developer community and provide answers and different solutions. Apart from that, I am just another normal developer with a laptop, a mug of coffee, some biscuits and a thick spectacle!

GitHub

Verwandter Artikel - PostgreSQL Function