it-swarm.com.de

Wie verwende ich currval () in PostgreSQL, um die zuletzt eingefügte ID zu erhalten?

Ich habe einen Tisch:

CREATE TABLE names (id serial, name varchar(20))

Ich möchte die "zuletzt eingefügte ID" aus dieser Tabelle, ohne beim Einfügen RETURNING id Zu verwenden. Es scheint eine Funktion zu geben CURRVAL() , aber ich verstehe nicht, wie man sie benutzt.

Ich habe versucht mit:

SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)

aber keiner von ihnen funktioniert. Wie kann ich currval() verwenden, um die zuletzt eingefügte ID abzurufen?

70
Jonas

Wenn Sie eine Spalte als serial erstellen, erstellt PostgreSQL automatisch eine Sequenz dafür.

Der Name der Sequenz wird automatisch generiert und lautet immer tablename_columnname_seq. In Ihrem Fall lautet die Sequenz name names_id_seq.

Nach dem Einfügen in die Tabelle können Sie currval() mit folgendem Sequenznamen aufrufen:

postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
CREATE TABLE
postgres=> insert into names (name) values ('Arthur Dent');
INSERT 0 1
postgres=> select currval('names_id_seq');
 currval
---------
       1
(1 row)
postgres=>

Anstatt den Sequenznamen fest zu codieren, können Sie stattdessen auch pg_get_serial_sequence() verwenden:

select currval(pg_get_serial_sequence('names', 'id'));

Auf diese Weise müssen Sie sich nicht auf die von Postgres verwendete Namensstrategie verlassen.

Oder wenn Sie den Sequenznamen überhaupt nicht verwenden möchten, verwenden Sie lastval()

56

Dies ist direkt von Stapelüberlauf

Wie von @a_horse_with_no_name und @Jack Douglas hervorgehoben, funktioniert currval nur mit der aktuellen Sitzung. Wenn Sie also mit der Tatsache einverstanden sind, dass das Ergebnis möglicherweise von einer nicht festgeschriebenen Transaktion einer anderen Sitzung beeinflusst wird und Sie dennoch etwas möchten, das sitzungsübergreifend funktioniert, können Sie Folgendes verwenden:

SELECT last_value FROM your_sequence_name;

Verwenden Sie den Link zu SO für weitere Informationen.

Aus Postgres-Dokumentation geht jedoch klar hervor, dass

Es ist ein Fehler, lastval aufzurufen, wenn nextval in der aktuellen Sitzung noch nicht aufgerufen wurde.

Um genau zu sein, um currval oder last_value für eine Sequenz über Sitzungen hinweg richtig zu verwenden, müssten Sie so etwas tun?

SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);

Vorausgesetzt natürlich, Sie haben in der aktuellen Sitzung keine Einfügung oder eine andere Möglichkeit, das serielle Feld zu verwenden.

53
Slak

Sie müssen nextval für diese Sequenz in dieser Sitzung vor currval aufrufen :

create sequence serial;
select nextval('serial');
 nextval
---------
       1
(1 row)

select currval('serial');
 currval
---------
       1
(1 row)

daher können Sie die 'zuletzt eingefügte ID' in der Sequenz nur finden, wenn insert in derselben Sitzung ausgeführt wird (eine Transaktion wird möglicherweise zurückgesetzt, die Sequenz jedoch nicht).

wie in der Antwort von a_horse ausgeführt, create table mit einer Spalte vom Typ serial erstellt automatisch eine Sequenz und generiert daraus den Standardwert für die Spalte, sodass ein insert normalerweise implizit auf nextval zugreift:

create table my_table(id serial);
NOTICE:  CREATE TABLE will create implicit sequence "my_table_id_seq" for 
         serial column "my_table.id"

\d my_table
                          Table "stack.my_table"
 Column |  Type   |                       Modifiers
--------+---------+-------------------------------------------------------
 id     | integer | not null default nextval('my_table_id_seq'::regclass)

insert into my_table default values;
select currval('my_table_id_seq');
 currval
---------
       1
(1 row)

Es gibt also einige Probleme mit diesen verschiedenen Methoden:

Currval erhält nur den zuletzt in der aktuellen Sitzung generierten Wert. Dies ist ideal, wenn Sie keine anderen Werte generieren, aber in Fällen, in denen Sie möglicherweise einen Trigger aufrufen und/oder die Sequenz in der aktuellen Transaktion mehrmals vorrücken lassen wird nicht den richtigen Wert zurückgeben. Das ist kein Problem für 99% der Leute da draußen - aber es ist etwas, das man berücksichtigen sollte.

Der beste Weg, um die eindeutige Kennung nach einer Einfügeoperation zuzuweisen, ist die Verwendung der RETURNING-Klausel. Im folgenden Beispiel wird davon ausgegangen, dass die an die Sequenz gebundene Spalte "id" heißt:

insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;

Beachten Sie, dass die Nützlichkeit der RETURNING-Klausel weit über das Abrufen der Sequenz hinausgeht, da sie auch:

  • Rückgabewerte, die für die "endgültige Einfügung" verwendet wurden (nachdem beispielsweise ein BEFORE-Trigger die eingefügten Daten möglicherweise geändert hat.)
  • Geben Sie die Werte zurück, die gelöscht wurden:

    aus Tabelle A löschen, wobei id> 100 zurückgibt *

  • Geben Sie die geänderten Zeilen nach einem UPDATE zurück:

    tabelle aktualisieren Eine Menge X = 'y' wobei blah = 'blech' zurückgibt *

  • Verwenden Sie das Ergebnis eines Löschvorgangs für ein Update:

    WITH A as (Löschen * aus Tabelle A als Rückgabe-ID) Update B set deleted = true wobei ID in (ID aus A auswählen);

3
chander

Sie müssen GRANT Verwendung im Schema wie folgt:

GRANT USAGE ON SCHEMA schema_name to user;

und

GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;
1
AMML

Wenn Sie den Wert der Sequenzen erhalten möchten, ohne nextval() aufgerufen zu haben und ohne die Sequenz ändern zu müssen, habe ich eine PL/pgSQL-Funktion zusammengestellt, um damit umzugehen: Finden Sie den Wert aller Datenbanksequenzen

1
Christophe

Ich musste trotz SQLALchemy eine Abfrage ausführen, da ich currval nicht erfolgreich verwenden konnte.

nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1

Dies war ein python flask + Postgresql-Projekt).

1
Jalal

In PostgreSQL 11.2 können Sie die Sequenz wie eine Tabelle behandeln:

Beispiel, wenn Sie eine Sequenz mit dem Namen 'names_id_seq' haben

select * from names_id_seq;
 last_value | log_cnt | is_called
------------+---------+-----------
          4 |      32 | t
(1 row)

Das sollte Ihnen die zuletzt eingefügte ID geben (in diesem Fall 4), was bedeutet, dass der aktuelle Wert (oder der Wert, der für die nächste ID verwendet werden sollte) 5 sein sollte.

0
scifisamurai