PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Funzione PostgreSQL per l'ultimo ID inserito

( tl;dr :vai all'opzione 3:INSERT con RETURNING )

Ricordiamo che in postgresql non esiste un concetto di "id" per le tabelle, solo sequenze (che sono tipicamente, ma non necessariamente, usati come valori predefiniti per chiavi primarie surrogate, con lo pseudo-tipo SERIAL).

Se sei interessato a ottenere l'ID di una riga appena inserita, ci sono diversi modi:

Opzione 1:CURRVAL(<sequence name>); .

Ad esempio:

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval('persons_id_seq');

Il nome della sequenza deve essere noto, è davvero arbitrario; in questo esempio assumiamo che la tabella persons ha un id colonna creata con il SERIAL pseudo-tipo. Per evitare di fare affidamento su questo e sentirti più pulito, puoi usare invece pg_get_serial_sequence :

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval(pg_get_serial_sequence('persons','id'));

Avvertenza:currval() funziona solo dopo un INSERT (che ha eseguito nextval() ), nella stessa sessione .

Opzione 2:LASTVAL();

È simile alla precedente, solo che non è necessario specificare il nome della sequenza:cerca la sequenza modificata più recente (sempre all'interno della sessione, stesso avvertimento di cui sopra).

Entrambi CURRVAL e LASTVAL sono totalmente simultanei sicuri. Il comportamento della sequenza in PG è progettato in modo che sessioni diverse non interferiscano, quindi non c'è rischio di condizioni di gara (se un'altra sessione inserisce un'altra riga tra il mio INSERT e il mio SELECT, ottengo comunque il mio valore corretto).

Tuttavia hanno un sottile problema potenziale. Se il database ha qualche TRIGGER (o REGOLA) che, all'inserimento in persons table, effettua degli inserimenti extra in altre tabelle... quindi LASTVAL probabilmente ci darà il valore sbagliato. Il problema può verificarsi anche con CURRVAL , se gli inserimenti extra vengono eseguiti nelle stesse persons table (questo è molto meno usuale, ma il rischio esiste ancora).

Opzione 3:INSERT con RETURNING

INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;

Questo è il modo più pulito, efficiente e sicuro per ottenere l'ID. Non ha nessuno dei rischi del precedente.

Svantaggi? Quasi nessuno:potrebbe essere necessario modificare il modo in cui chiami la tua istruzione INSERT (nel peggiore dei casi, forse il tuo livello API o DB non si aspetta che un INSERT restituisca un valore); non è SQL standard (chi se ne frega); è disponibile da Postgresql 8.2 (dicembre 2006...)

Conclusione:se puoi, scegli l'opzione 3. Altrove, preferisci 1.

Nota:tutti questi metodi sono inutili se intendi ottenere l'ultimo ID inserito a livello globale (non necessariamente dalla tua sessione). Per questo, devi ricorrere a SELECT max(id) FROM table (ovviamente, questo non leggerà inserti non vincolati da altre transazioni).

Al contrario, dovresti mai usa SELECT max(id) FROM table invece una delle 3 opzioni sopra, per ottenere l'id appena generato dal tuo INSERT dichiarazione, perché (a parte le prestazioni) questo non è sicuro concorrente:tra il tuo INSERT e il tuo SELECT un'altra sessione potrebbe aver inserito un altro record.