( tl;dr
:ga naar optie 3:INSERT met RETURNING )
Bedenk dat er in postgresql geen "id"-concept voor tabellen is, alleen reeksen (die doorgaans, maar niet noodzakelijkerwijs, worden gebruikt als standaardwaarden voor surrogaat-primaire sleutels, met het pseudo-type SERIAL).
Als u geïnteresseerd bent in het verkrijgen van de id van een nieuw ingevoegde rij, zijn er verschillende manieren:
Optie 1:CURRVAL(<sequence name>);
.
Bijvoorbeeld:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
De naam van de reeks moet bekend zijn, het is echt willekeurig; in dit voorbeeld gaan we ervan uit dat de tabel persons
heeft een id
kolom gemaakt met de SERIAL
pseudo-type. Om te voorkomen dat je hierop vertrouwt en om je schoner te voelen, kun je in plaats daarvan pg_get_serial_sequence
gebruiken :
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Waarschuwing:currval()
werkt alleen na een INSERT
(die nextval()
. heeft uitgevoerd ), in dezelfde sessie .
Optie 2:LASTVAL();
Dit is vergelijkbaar met het vorige, alleen hoeft u de naam van de reeks niet op te geven:het zoekt naar de meest recent gewijzigde reeks (altijd binnen uw sessie, hetzelfde voorbehoud als hierboven).
Beide CURRVAL
en LASTVAL
zijn volledig gelijktijdig veilig. Het gedrag van de volgorde in PG is zo ontworpen dat verschillende sessies niet interfereren, dus er is geen risico op race-omstandigheden (als een andere sessie een andere rij tussen mijn INSERT en mijn SELECT invoegt, krijg ik nog steeds mijn juiste waarde).
Echter ze hebben een subtiel potentieel probleem. Als de database een TRIGGER (of RULE) heeft die, bij invoeging in persons
tabel, maakt wat extra invoegingen in andere tabellen... dan LASTVAL
zal ons waarschijnlijk de verkeerde waarde geven. Het probleem kan zelfs optreden met CURRVAL
, als de extra toevoegingen worden gedaan in dezelfde persons
tabel (dit is veel minder gebruikelijk, maar het risico bestaat nog steeds).
Optie 3:INSERT
met RETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Dit is de meest schone, efficiënte en veilige manier om de id te verkrijgen. Het heeft geen van de risico's van het vorige.
nadelen? Bijna geen:u moet mogelijk de manier wijzigen waarop u uw INSERT-instructie aanroept (in het ergste geval verwacht uw API- of DB-laag misschien niet dat een INSERT een waarde retourneert); het is geen standaard SQL (wat maakt het uit); het is beschikbaar sinds Postgresql 8.2 (december 2006...)
Conclusie:als je kunt, ga dan voor optie 3. Elders liever 1.
Opmerking:al deze methoden zijn nutteloos als u van plan bent om de laatst ingevoerde id globaal te krijgen (niet noodzakelijk door uw sessie). Hiervoor moet je je toevlucht nemen tot SELECT max(id) FROM table
(uiteraard leest dit geen niet-vastgelegde inserts van andere transacties).
Omgekeerd moet u nooit gebruik SELECT max(id) FROM table
in plaats van een van de 3 bovenstaande opties, om de id te krijgen die zojuist is gegenereerd door uw INSERT
verklaring, omdat dit (afgezien van de prestaties) niet gelijktijdig veilig is:tussen uw INSERT
en je SELECT
een andere sessie heeft mogelijk een ander record ingevoegd.