Newsgroup: it.comp.software.database
Titolo: [Postgres] ottenere ID autogenerato

Buongiorno a tutti!
Sto accedendo via JDBC ad un database PostgreSQL (credo 7.4) ed ho bisogno
di conoscere la chiave primaria generata come autonumber dal database
all'atto di creare un nuovo record.
Con Java ho la possibilità di averla come risposta all'operazione di
inserimento ma ottengo un errore di Postgres che dice che la funzionalità
non è (ancora) implementata.
Per ora uso un metodo "ugly" dove ri-interrogo il database con gli stessi
dati appena inseriti.
Esiste un metodo più pulito e corretto? Stored procedure? Conosco SQL ma
non so da dove partire per creare una stored procedure in Postgres.
Grazie per l'attenzione!
Alex.
-- 
___________________________________________________________
a p bertolini
(
www.webwarrior.org
)

 
No, la cosa migliore č gestire l'incremento invece che lasciarlo fare al 
DB in questi casi.
Fai una doppia operazione: prima ottieni l'id da usare per l'inserimento 
con una select sulla sequence relativa, e poi fai l'insert specificando 
tu l'id.
i.e. supponendo di avere una tabella cosě fatta:
Table "pippo"
-[ RECORD 1 ]---------------------------------------------------
Attribute | chiave
Type      | integer
Modifier  | not null default nextval('"pippo_chiave_seq"'::text)
-[ RECORD 2 ]---------------------------------------------------
Attribute | nome
Type      | text
Modifier  |
Index: pippo_chiave_key
invece che fare
"insert into pippo (nome) values ('gino')";
e poi cercare di recuperare l'id di Gino fai:
"select nextval('"pippo_chiave_seq"'::text) as chiave"
te lo metti in una bella variabilina e poi fai:
insert into pippo values (chiave, 'gino');
e hai risolto il problema alla radice...
-- 
Fabrizio "Hermooz" Ermini


:Provate a guardare gli ingredienti del famoso Labello che si usa per
:le labbra screpolate: Butirrospermum Parkii (sperma di maiale).

Grazie a entrambi!
Non sapevo che Postgres non avesse gli autonumber (non ho implementato io
il DB)


 test=> select currval('test_x_seq');
Leonardo, correggimi se sbaglio ma per usare questa tecnica devi dirgli 
anche di fare il tutto all'interno di un blocco transazionale 
"begin...commit", no?
Altrimenti non sono sicuro che si sia a posto per la concorrenza 
(l'incertezza è data dal fatto che non ho seguito nelle versioni recenti 
di PG come viene gestita l'assegnazione delle sequence alle varie 
sessioni)...
-- 
Fabrizio "Hermooz" Ermini


Alex


sessioni)...
Mi hai messo un dubbio corrosivo :-)
Da quel che leggo, nextval e currval sarebbero qualcosa di al di fuori
delle normali transazioni:
: To avoid blocking of concurrent transactions that obtain numbers from
: the same sequence, a nextval operation is never rolled back; that is,
: once a value has been fetched, it is considered used, even if the
: transaction that did the nextval later aborts.
: This means that aborted transactions may leave unused "holes" in the
: sequence of assigned values. setval operations are never rolled back,
: either. 
In pratica, un INSERT effettua un nextval() atomico implicito, per cui
(se ho capito bene) i currval successivi ritornano il valore corretto,
anche in assenza di transazioni.
Tutto questo non sarebbe piu' vero in ambienti piu' complessi, come in
presenza di un multiplexer N:M, ma in quel caso non useremmo un codice
come questo (o il multiplexer provvederebbe lui a fare il dovuto).
Leonardo
-- 
Nach doiligh domhsa mo chailin a mholadh
'S ni he amhain mar bhi si or
Bhi si mar gath greine a dhul in eadan na gloinne
Is bhi sceimh mhna na finne le mo cailin or


Stando alla documentazione credo sia implicito il contrario. Ripeto: credo.
In caso di inserimenti concorrenti (processi A e B) potresti ritrovarti con
una sequenza di operazioni sul DB del tipo
A: INSERT INTO test ...
B: INSERT INTO test ...
A: SELECT currval('test_x_seq');
B: SELECT currval('test_x_seq');
A e B otterrebbero lo stesso sequence number, solo B avrebbe quello
corretto, ma si tratterebbe di un caso.
Credo che fare una piccola transazione con una INSERT ed una SELECT dell'ID
non gravi eccessivamente sulle risorse, meglio andare sul sicuro.


 come questo (o il multiplexer provvederebbe lui a fare il dovuto).
Non so cos'e' un multiplexer N:M :-/
bye!
-- 
Fabrizio "Hermooz" Ermini

corretto, ma si tratterebbe di un caso.
No, e' per quello che parlavo di multiplexer. A quanto pare ogni sessione
riceve un 'currval' suo proprio. In ambiente multiplexato, con N client e
M sessioni al database, la faccenda si complicherebbe (ma, probabilmente,
il multiplexer risolverebbe serializzando e riordinando le transazioni, e
associando ogni operazione transactionless ma rischiosa - come questa - a
una sessione sua propria).
Comunque ho fatto la prova su un database fresco e sacrificabile:
A root=> CREATE TABLE pippo ( x serial, y integer );
A NOTICE:  CREATE TABLE will create implicit sequence "pippo_x_seq" for
A "serial" column "pippo.x"
A CREATE TABLE
B root=> insert into pippo (y) values (12);
B INSERT 17197 1
B root=> select currval('pippo_x_seq');
B currval
B ---------
B       1
B (1 row)
A root=> INSERT INTO pippo (y) values (5);
A INSERT 17198 1
B root=> insert into pippo (y) values (6);
B INSERT 17199 1
A root=> SELECT currval('pippo_x_seq');
A currval
A ---------
A       2
A (1 row)
B root=> select currval('pippo_x_seq');
B currval
B ---------
B       3
B (1 row)


 una sessione sua propria).
Purtroppo non so nulla di multiplexer. Il tuo discorso č ragionevolissimo e
sarei sorpreso se le cose non fossero cosě... speriamo che queste
conclusioni siano assicurate da una qualche documentazione PostgreSQL.
Grazie! (anche per il test!)
Alex


Purtroppo non so nulla di multiplexer.
Sono degli accrocchi per poveri :-) (senza offesa, si fa per scherzare)
che servono nel caso che, per problemi di licenza, rete, o chissa' cos'
altro, tu non possa aprire piu' di N connessioni concorrenti.
Oppure aprire una connessione ti costi un capitale in CPU o altro.
Allora il multiplexer apre lui <= N connessioni, e poi tu ti colleghi a
lui.
Chiaramente, un multiplexer non puo' essere un bieco "concentratore" di
statement SQL, ma li deve saper riordinare/serializzare con giudizio in
modo da non avere effetti collaterali devastanti, quali mandare appunto
una INSERT alla connessione #2 e la SELECT CURRVAL alla #3.
Personalmente, m'hanno sempre lasciato freddino (affermazione disonesta
per due motivi: (a) ne ho provati due, in tutto; (b) uno potrebbe anche
dire che sto rosicando perche' non m'e' riuscito di farli andare, e chi
sa, potrebbe avere ragione).
Negli anni, sono arrivato ad avvicinarmi alle posizioni microsoftiane e
a concludere che acquistarne uno, montarlo e imparare a usarlo (che poi
hanno le loro ubbie, tipo, non puoi fare transazioni cosi' o cosa'... o
devi transazionare tutto... o devi fare le query in un dato modo...) ti
costa di piu' che passare ad un quad-Athlon FX2 con doppio carburatore,
cilindri a V e cerchi in lega :-)


 
In altre parole è un layer software (o HW, non ho capito) che permette 
di fare connection pooling anche quando non si dispone di un application 
server? Anche se dici che le implementazioni che hai provato non erano 
soddisfacenti, l'idea non è male... puntatori?


server?
Software, si'. E' passato del tempo, sicche' mi sono aggiornato: .NET ce
l'avrebbe di serie
http://www.winnetmag.com/SQLServer/Article/ArticleID/38356/38356.html
e Postgres avrebbe qualcosa di simile via JDBCPool.
A dir la verita', non ricordo bene nemmeno come si chiamava, il coso che
usai per ultimo -- si interfacciava a Microsoft SQL Server, pero'. Crash
che pareva il giorno del castigo; ma era il primissimo SQL Server, forse
aveva ancora dentro il copyright originale di Sybase :-), e da allora e'
passata molta acqua sotto i ponti...
Leonardo vecchio
