Wie kann ich in PostgreSQL die letzte ID in eine Tabelle einfügen?
In MS SQL gibt es SCOPE_IDENTITY ().
Bitte raten Sie mir nicht, so etwas zu verwenden:
select max(id) from table
Wie kann ich in PostgreSQL die letzte ID in eine Tabelle einfügen?
In MS SQL gibt es SCOPE_IDENTITY ().
Bitte raten Sie mir nicht, so etwas zu verwenden:
select max(id) from table
Antworten:
( tl;dr
: gehe zu Option 3: EINFÜGEN mit RÜCKGABE)
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 SERIAL- Pseudotyp verwendet werden).
Wenn Sie die ID einer neu eingefügten Zeile abrufen möchten, gibt es verschiedene 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 wird davon ausgegangen, dass für die Tabelle persons
eine id
Spalte mit dem SERIAL
Pseudotyp erstellt wurde. Um sich nicht darauf zu verlassen und sich sauberer zu fühlen, können Sie stattdessen Folgendes verwenden pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Vorsichtsmaßnahme: Funktioniert currval()
nur nach einer INSERT
(ausgeführten nextval()
) Sitzung in derselben Sitzung .
Option 2: LASTVAL();
Dies ähnelt dem vorherigen, nur dass Sie den Sequenznamen nicht angeben müssen: Es wird nach der zuletzt geänderten Sequenz gesucht (immer innerhalb Ihrer Sitzung, dieselbe Einschränkung wie oben).
Beide CURRVAL
undLASTVAL
sind absolut gleichzeitig sicher. Das Verhalten der Sequenz in PG ist so konzipiert, dass andere Sitzungen nicht stören, sodass kein Risiko für Rennbedingungen besteht (wenn eine andere Sitzung eine weitere Zeile zwischen meinem INSERT und meinem SELECT einfügt, erhalte ich immer noch meinen korrekten Wert).
Sie haben jedoch ein subtiles potenzielles Problem. Wenn die Datenbank einen TRIGGER (oder eine REGEL) enthält, der beim Einfügen in eine persons
Tabelle einige zusätzliche Einfügungen in andere Tabellen vornimmt LASTVAL
, erhalten wir wahrscheinlich den falschen Wert. Das Problem kann sogar auftreten CURRVAL
, wenn die zusätzlichen Einfügungen in dieselbe persons
Tabelle vorgenommen werden (dies ist viel weniger üblich, aber das Risiko besteht weiterhin).
Option 3: INSERT
mitRETURNING
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 der vorherigen.
Nachteile? Fast keine: Möglicherweise müssen Sie die Art und Weise ändern, in der 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 verfügbar seit Postgresql 8.2 (Dez 2006 ...)
Fazit: Wenn Sie können, wählen Sie Option 3. An anderer Stelle bevorzugen Sie 1.
Hinweis: Alle diese Methoden sind nutzlos, wenn Sie die zuletzt eingefügte ID global abrufen möchten (nicht unbedingt von Ihrer Sitzung). Dazu müssen Sie darauf zurückgreifen SELECT max(id) FROM table
(dies liest natürlich keine nicht festgeschriebenen Einfügungen aus anderen Transaktionen).
Umgekehrt sollten Sie nie benutzen , SELECT max(id) FROM table
anstatt eine der drei oben genannten Optionen, die ID nur von Euren zu bekommen INSERT
Aussage, weil sie (abgesehen von Leistung) nicht gleichzeitig sicher ist: zwischen Ihrer INSERT
und Ihrer SELECT
anderen Sitzung möglicherweise einem anderen Datensatz eingefügt haben.
SELECT max(id)
erledigt den Job leider auch nicht, sobald Sie anfangen, Zeilen zu löschen.
1,2,3,4,5
und die Zeilen 4 und 5 löschen, ist die zuletzt eingefügte ID immer noch 5, gibt aber max()
3 zurück.
RETURNING id;
man dies in eine andere Tabelle einfügt, wäre willkommen!
RETURNING id
ein SQL-Skript verwenden, das dem psql
Befehlszeilentool zugeführt wird ?
Siehe die RETURNING-Klausel der INSERT- Anweisung. Grundsätzlich dient INSERT auch als Abfrage und gibt Ihnen den eingefügten Wert zurück.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
, gibt es einfach id aus, als ob Sie select id from names where id=$lastid
direkt ausgeführt hätten. Wenn Sie die Rückgabe in einer Variablen speichern möchten , ist insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
die Anweisung, die die Rückgabe enthält, die letzte Anweisung in einer Funktion , und die ID, die bearbeitet wird returning
, wird von der gesamten Funktion zurückgegeben.
Sie können die RETURNING-Klausel in der INSERT-Anweisung wie folgt verwenden
wgzhao=# create table foo(id int,name text);
CREATE TABLE
wgzhao=# insert into foo values(1,'wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into foo values(3,'wgzhao') returning id;
id
----
3
(1 row)
INSERT 0 1
wgzhao=# create table bar(id serial,name text);
CREATE TABLE
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
2
(1 row)
INSERT 0
Leonbloys Antwort ist ziemlich vollständig. Ich würde nur den Sonderfall hinzufügen, in dem der zuletzt eingefügte Wert aus einer PL / pgSQL-Funktion abgerufen werden muss, in der OPTION 3 nicht genau passt.
Zum Beispiel, wenn wir die folgenden Tabellen haben:
CREATE TABLE person(
id serial,
lastname character varying (50),
firstname character varying (50),
CONSTRAINT person_pk PRIMARY KEY (id)
);
CREATE TABLE client (
id integer,
CONSTRAINT client_pk PRIMARY KEY (id),
CONSTRAINT fk_client_person FOREIGN KEY (id)
REFERENCES person (id) MATCH SIMPLE
);
Wenn wir einen Kundendatensatz einfügen müssen, müssen wir uns auf einen Personendatensatz beziehen. Angenommen, wir möchten eine PL / pgSQL-Funktion entwickeln, die einen neuen Datensatz in den Client einfügt, sich aber auch um das Einfügen des neuen Personendatensatzes kümmert. Dafür müssen wir eine kleine Variation von Leonbloys OPTION 3 verwenden:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
Beachten Sie, dass es zwei INTO-Klauseln gibt. Daher würde die PL / pgSQL-Funktion wie folgt definiert:
CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying)
RETURNS integer AS
$BODY$
DECLARE
v_id integer;
BEGIN
-- Inserts the new person record and retrieves the last inserted id
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO v_id;
-- Inserts the new client and references the inserted person
INSERT INTO client(id) VALUES (v_id);
-- Return the new id so we can use it in a select clause or return the new id into the user application
RETURN v_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Jetzt können wir die neuen Daten einfügen mit:
SELECT new_client('Smith', 'John');
oder
SELECT * FROM new_client('Smith', 'John');
Und wir bekommen die neu erstellte ID.
new_client
integer
----------
1
Siehe das folgende Beispiel
CREATE TABLE users (
-- make the "id" column a primary key; this also creates
-- a UNIQUE constraint and a b+-tree index on the column
id SERIAL PRIMARY KEY,
name TEXT,
age INT4
);
INSERT INTO users (name, age) VALUES ('Mozart', 20);
Um die zuletzt eingefügte ID zu erhalten, verwenden Sie diese für die Tabelle "Benutzer".
SELECT currval(pg_get_serial_sequence('users', 'id'));
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
Sie müssen natürlich den Tabellennamen und den Spaltennamen angeben.
Dies gilt für die aktuelle Sitzung / Verbindung http://www.postgresql.org/docs/8.3/static/functions-sequence.html
Versuche dies:
select nextval('my_seq_name'); // Returns next value
Wenn dies 1 zurückgibt (oder was auch immer der Startwert für Ihre Sequenz ist), setzen Sie die Sequenz auf den ursprünglichen Wert zurück und übergeben Sie das falsche Flag:
select setval('my_seq_name', 1, false);
Andernfalls,
select setval('my_seq_name', nextValue - 1, true);
Dadurch wird der Sequenzwert auf den ursprünglichen Zustand zurückgesetzt und "setval" wird mit dem von Ihnen gesuchten Sequenzwert zurückgegeben.
Postgres verfügt über einen integrierten Mechanismus für denselben, der in derselben Abfrage die ID oder was auch immer Sie zurückgeben möchten, zurückgibt. Hier ist ein Beispiel. Angenommen, Sie haben eine Tabelle mit 2 Spalten Spalte1 und Spalte2 erstellt und möchten, dass Spalte1 nach jeder Einfügung zurückgegeben wird.
# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
id
----
1
(1 row)
# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
id
----
2
(1 row)
Ich hatte dieses Problem mit Java und Postgres. Ich habe es behoben, indem ich eine neue Connector-J-Version aktualisiert habe.
postgresql-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/download.html : Version 42.2.12