( tl;dr
:přejděte na možnost 3:INSERT with RETURNING )
Připomeňme, že v postgresql neexistuje žádný koncept „id“ pro tabulky, pouze sekvence (které se obvykle, ale ne nutně, používají jako výchozí hodnoty pro náhradní primární klíče s pseudotypem SERIAL).
Pokud máte zájem získat ID nově vloženého řádku, existuje několik způsobů:
Možnost 1:CURRVAL(<sequence name>);
.
Například:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
Název sekvence musí být znám, je opravdu libovolný; v tomto příkladu předpokládáme, že tabulka persons
má id
sloupec vytvořený pomocí SERIAL
pseudotyp. Abyste se na to nespoléhali a abyste se cítili čistěji, můžete místo toho použít pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Upozornění:currval()
funguje pouze po INSERT
(který provedl nextval()
), ve stejné relaci .
Možnost 2:LASTVAL();
Toto je podobné předchozímu, jen nemusíte specifikovat název sekvence:hledá nejnovější upravenou sekvenci (vždy uvnitř vaší relace, stejné upozornění jako výše).
Oba CURRVAL
a LASTVAL
jsou současně zcela bezpečné. Chování sekvence v PG je navrženo tak, že různé relace nebudou rušit, takže nehrozí žádné závodní podmínky (pokud jiná relace vloží další řádek mezi můj INSERT a můj SELECT, stále dostanu svou správnou hodnotu).
Nicméně mají jemný potenciální problém. Pokud má databáze nějaký SPUŠTĚČ (nebo PRAVIDLO), který při vložení do persons
table, provede nějaké další vložení do jiných tabulek... pak LASTVAL
pravděpodobně nám dá špatnou hodnotu. Problém může dokonce nastat s CURRVAL
, pokud jsou další vkládání prováděna do stejných persons
tabulka (toto je mnohem méně obvyklé, ale riziko stále existuje).
Možnost 3:INSERT
s RETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Toto je nejčistší, nejúčinnější a nejbezpečnější způsob, jak získat ID. Nemá žádná rizika předchozího.
Nevýhody? Téměř žádné:možná budete muset upravit způsob, jakým voláte příkaz INSERT (v nejhorším případě možná vaše vrstva API nebo DB neočekává, že INSERT vrátí hodnotu); není to standardní SQL (koho to zajímá); je k dispozici od Postgresql 8.2 (prosinec 2006...)
Závěr:Pokud můžete, přejděte na možnost 3. Jinde preferujte 1.
Poznámka:všechny tyto metody jsou k ničemu, pokud máte v úmyslu získat poslední vložené id globálně (ne nutně vaší relací). K tomu se musíte uchýlit k SELECT max(id) FROM table
(samozřejmě to nebude číst nepotvrzené vložky z jiných transakcí).
Naopak byste neměli nikdy použijte SELECT max(id) FROM table
místo jedné ze 3 výše uvedených možností, abyste získali ID právě vygenerované vaším INSERT
prohlášení, protože (kromě výkonu) to není souběžné bezpečné:mezi vaším INSERT
a váš SELECT
jiná relace mohla vložit další záznam.