headermask image

header image

Database, campi ad autoincremento ed INSERT

Mi trovo, mio malgrado, a sviluppare una applicazione web in PHP per gestire un impianto. Le ragioni che mi hanno portato a questo sono troppo lunghe da spiegare, per cui andiamo al sodo.

Alle spalle dell’applicazione vi è un database PostgreSQL per mantenere lo stato e la coerenza del flusso di lavorazione (è una applicazione di gestione di processo). Alcune tabelle nel database hanno un campo ad autoincremento, che in PostgreSQL è definito dal tipo serial (esiste anche in MySQL ed è un alias equivalente a: BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE). Questo campo ha la caratteristica interessante che al momento di una query INSERT se viene omesso dai dati da inserire nel nuovo record, viene assegnato automaticamente da PostgreSQL con l’intero successivo all’ultimo usato, partendo da 1. Per intenderci: il primo INSERT lo assegnerà al valore 1, il secondo al 2, il terzo a 3 e via così. Questo garantisce che non vi saranno duplicati, e quindi il campo si può usare come identificativo univoco. Tant’è che nelle tabelle in questione il campo l’ho chiamato ID, con la solita mancanza di fantasia.

Fin qui nulla di strano, ma… Dopo una query di INSERT, a parte controllare se sia andata a buon fine, se mi serve di sapere quale ID è stato assegnato al record inserito come faccio? Sulle prime avevo ingenuamente (e molto inespertamente) pensato di fare una query con gli stessi valori inseriti e vedere che ID mi restituiva. Ma vi potevano essere record con valori uguali tranne l’ID, quindi questa soluzione non va. Poi ho pensato di usare il MAX sull’intera colonna degli ID, ed anche qui vi potevano essere parecchie controindicazioni.

Poi, come sempre accade, invece di smanettare a cervello spento, mi sono fatto la domanda chiave: possibile che non esista una funzione nativa apposita? Ebbene, esiste ed è proprio quello che serve, oltre ad essere assolutamente corretta anche in caso di inserimenti multipli concorrenti sulla stessa tabella. La funzione è currval in PostgreSQL e LAST_INSERT_ID in MySQL. In entrambi i database la funzione è isolata per connessione al database, quindi anche in caso di utilizzo concorrente con query di INSERT parallele, il valore restituito è coerente. Se si avessero dei dubbi, basta consultare la documentazione in merito, e alla peggio ricorrere ad una transazione per isolare l’operazione.

Come si usa è presto detto: appena dopo una query di INSERT, si controlla se è andata a buon fine, poi si esegue questa query (per PostgreSQL):


SELECT currval(tabella_id_seq) as id;

che andiamo a spiegare. Al momento della creazione di una tabella che contiene un campo di tipo serial, PostgreSQL crea implicitamente un oggetto sequence, che altro non è che un numero intero che conserva l’ultimo valore usato nel rispettivo campo di tipo serial. Il nome assegnato all’oggetto sequenza è il nome della tabella, seguito dal nome del campo e dalla stringa “seq”, separati da un segno di underscore. Se ad esempio la tabella si chiama libri ed il campo al suo interno di tipo serial si chiama idlibro, la sequenza implicitamente creata avrà come nome: libri_idlibro_seq. Quindi la query specifica per questa tabella per conoscere l’ultimo valore di idlibro generato da PostgreSQL sarà:


SELECT currval(libri_idlibro_seq) as ultimoid;

Molto più semplice che inventarsi funzioni apposite (dal funzionamento quanto mai incerto), o peggio inventare l’acqua calda, ossia scrivere codice per una funzione che esiste già nativa sul software che andiamo ad utilizzare.

Riferimenti

  • Il manuale di PostgreSQL
  • Il manuale di MySQL
  • Il manuale di PHP, alla voce pg_last_oid(), che indirizza alla funzione giusta, ossia currval

Se ti piace quello che scrivo registrati al feed RSS

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*
  • Licenza

    Creative Commons License
    Questo sito e tutti i suoi contenuti sono pubblicati sotto una Licenza Creative Commons, quando non diversamente specificato.

    Per altri usi, basta contattarmi.

  • Argomenti

  • Archivio mensile

  • Spazio offerto da

  • Alzate d'ingegno

    D: invece di usare il solito software pirata, hai provato OpenOffice?

    R: ho provato più volte a scaricarlo da Emule, ma ha sempre problemi.

  • Amici

  • Buonumore

  • Da leggere

  • Sicurezza e computer

  • Adesivi