( tl;dr
:Gehe zu Option 3:INSERT mit RETURNING )
Denken Sie daran, dass es in Postgresql kein „id“-Konzept für Tabellen gibt, sondern nur Sequenzen (die normalerweise, aber nicht unbedingt als Standardwerte für Ersatzprimärschlüssel mit dem Pseudotyp SERIAL verwendet werden).
Wenn Sie daran interessiert sind, die ID einer neu eingefügten Zeile zu erhalten, gibt es mehrere Möglichkeiten:
Option 1:CURRVAL(<sequence name>);
.
Zum Beispiel:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
Der Name der Sequenz muss bekannt sein, er ist wirklich willkürlich; In diesem Beispiel gehen wir davon aus, dass die Tabelle persons
hat eine id
mit dem SERIAL
erstellte Spalte Pseudotyp. Um sich nicht darauf verlassen zu müssen und sich sauberer zu fühlen, können Sie stattdessen pg_get_serial_sequence
verwenden :
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Achtung:currval()
funktioniert nur nach einem INSERT
(der nextval()
ausgeführt hat ), in derselben Sitzung .
Möglichkeit 2:LASTVAL();
Dies ähnelt dem vorherigen, nur dass Sie den Sequenznamen nicht angeben müssen:Es sucht nach der zuletzt geänderten Sequenz (immer in Ihrer Sitzung, gleiche Einschränkung wie oben).
Sowohl CURRVAL
und LASTVAL
sind völlig gleichzeitig sicher. Das Verhalten der Sequenz in PG ist so ausgelegt, dass verschiedene Sitzungen nicht stören, sodass kein Risiko von Race-Conditions besteht (wenn eine andere Sitzung eine weitere Zeile zwischen meinem INSERT und meinem SELECT einfügt, erhalte ich immer noch meinen korrekten Wert).
Allerdings Sie haben ein subtiles potenzielles Problem. Wenn die Datenbank einen TRIGGER (oder eine REGEL) hat, wird beim Einfügen in persons
Tabelle, macht einige zusätzliche Einfügungen in andere Tabellen ... dann LASTVAL
wird uns wahrscheinlich den falschen Wert geben. Das Problem kann sogar mit CURRVAL
auftreten , wenn die zusätzlichen Einfügungen in denselben persons
vorgenommen werden Tabelle (dies ist viel seltener, aber das Risiko besteht immer noch).
Möglichkeit 3:INSERT
mit RETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Dies ist der sauberste, effizienteste und sicherste Weg, um die ID zu erhalten. Es hat keine der Risiken des vorherigen.
Nachteile? Fast keine:Möglicherweise müssen Sie die Art und Weise ändern, wie Sie Ihre INSERT-Anweisung aufrufen (im schlimmsten Fall erwartet Ihre API- oder DB-Schicht möglicherweise nicht, dass ein INSERT einen Wert zurückgibt). es ist kein Standard-SQL (wen interessiert das); es ist seit Postgresql 8.2 (Dezember 2006...) verfügbar
Fazit:Wenn Sie können, entscheiden Sie sich für Option 3. Ansonsten bevorzugen Sie 1.
Hinweis:Alle diese Methoden sind nutzlos, wenn Sie beabsichtigen, die zuletzt eingefügte ID global zu erhalten (nicht unbedingt durch Ihre Sitzung). Dazu müssen Sie auf SELECT max(id) FROM table
zurückgreifen (Natürlich liest dies keine nicht festgeschriebenen Einfügungen von anderen Transaktionen).
Umgekehrt sollten Sie nie Verwenden Sie SELECT max(id) FROM table
stattdessen eine der 3 Optionen oben, um die ID zu erhalten, die gerade von Ihrem INSERT
generiert wurde -Anweisung, weil (abgesehen von der Leistung) dies nicht gleichzeitig sicher ist:zwischen Ihren INSERT
und Ihr SELECT
eine andere Sitzung könnte einen anderen Datensatz eingefügt haben.