Newsgroup: it.comp.lang.visual-basic
Titolo: Farsi restituire ID dopo Insert INTO

Ciao a tutti,
ho delle tabelle i cui ID *chiave* sono campi contatore (numerici
incrementati da un trigger).
Dato che il programma lavora in multi utenza, volevo sapere se c'era un
modo sicuro per farsi restituire il valore del contatore inserito.
Cioč io faccio:
Adocn.execute "INSERT INTO TABELLA (ID,DESCRIZIONE) VALUES (Null,'Pippo');"
Passando null il trigger aumenta il contatore e assegna l'id al rigo.
Per adesso rileggo subito dopo con un "SELECT MAX(ID) From tabella", con
una gestione di accessi tramite una tabella di flag.
Esiste qualche sistema piů sicuro per evitare che due utenti in precisa
contemporanea non facciano funzionare la tabella flag e mi si incasinino
gli id?
Grazie

 gli id?
Fare un Select Max non è soltanto rischioso, è anche disastroso per le 
performance (a meno che non ci sia un indice clustered su ID), quando 
la tabella dovesse diventare popolosa.
Esistono 3 funzioni che restituiscono l'ultimo Identity inserito, a 
seconda dello scope a cui si vuole estendere il concetto di 'ultimo'.
Vedi, su BOL, Scope_Identity, e troverai i link alle altre due 
versioni.
Ciao
Alberto
-- 
A questo punto hanno trovato un muro,
un muro duro, molto molto duro,
che siamo noi.

 Esiste qualche sistema più sicuro per evitare che due utenti in precisa


 
http://community.visual-basic.it/lucianob/archive/2005/02/11/5476.aspx
Ti ringrazio, ho provato cosě ma non mi funziona
ADOCn.Execute "INSERT INTO FBANCHE (DESCBANCA) VALUES ('provaz')"
Set rs = New ADODB.Recordset
Set rs = ADOCn.Execute("SELECT SCOPE_IDENTITY()")
ed anche con SELECT @@IDENTITY AS nuovoID
Ora devo vedere se firebird supporta questo comando, o un'alternativa :\

 Ora devo vedere se firebird
Ecco, magari questo potevi dirlo all'inizio...
Non conosco quale funzione di FireBird offra questa funzionalità.
Ma se Sql-Server ne offre ben 3 diverse per ogni caso, vedrai che anche 
FireBird ne esporrà almeno una.
Tra l'altro, il Select @@Identity o quello che vuoi, va messo nello 
stesso batch dell'insert, cioè praticamente apri il recordset con uno 
stringone "INSERT ....  SELECT @@IDENTITY".


 FireBird ne esporrà almeno una.
Da quello che ho capito, dato che firebird offre i generatori (che su
sqlserver o sono nascosti o vengono gestiti diversamente), sono riuscito a
fare qualcosa del genere:
Set rs = ADOCn.Execute("select gen_id(IDBANCA_GEN, 1) as new_id from
rdb$database")
Questo mi incrementa il generatore di 1 e rs.fields(0) mi da il valore
incrementato.
In questo modo invece di fare le varie insert a ID=null, mi basterebbe
incrementare e prendere l'id con il comando di cui sopra, e fare la insert
into con l'id ricevuto
PS: fra l'istruzione di cui sopra e
'rs.ActiveConnection = ADOCn
'rs.Source = "select gen_id(IDBANCA_GEN, 1) as new_id from rdb$database"
'rs.Open
Che differenze pratiche ci sono?
Grazie

 Che differenze pratiche ci sono?
Se tu utilizzi SET davanti a rs.ActiveConnection = AdoCn, non cambia 
niente.
Ma se ti riferisci a quanto dicevo prima, in realtà stavo dicendo di 
fare anche l'Insert in un unico Execute.


 fare anche l'Insert in un unico Execute.
Quello sinceramente non ho ben capito come farlo:
Set rs = ADOCn.Execute("INSERT INTO FBANCHE (DESCBANCA) VALUES
('provaz');select gen_id(IDBANCA_GEN, 0) as new_id from rdb$database")
Non funge, ma immagino ci sia qualche metodo migliore.
Comunque se ho ben capito, il non plus ultra sarebbe fare una
stored-procedure per ogni insert delle varie tabelle che mi restituisca in
output l'eventuale id, ma forse mi resta più scomodo dato che il database
subisce spesso aggiunte di campi e tabelle per ora, quindi sarebbe più
scomodo da trattare e inviare gli aggiornamenti ai clienti (è più comodo
mandare un exe che un exe che esegua l'sql per aggiornare queste stored
procedure (sempre si possano definire da ado...))
Tnx
(presa da google)
| create procedure InsertAlgo ( 
|   campo2 varchar(x), 
|   campo3 varchar(x) 
| ) returns ( 
|   campo1 integer 
| ) 
| as 
| begin 
|   /* This makes sure you get it back correctly */ 
|   campo1 = gen_id(generador_de_algo, 1); 
| 
| 
|   /* Now, perform the insert with the unique value. */ 
|   insert into linea ( 
|     campo1, 
|     campo2, 
|     campo3 
|   ) values ( 
|     :campo1, 
|     :campo2, 
|     :campo3 
|   ); 
| 
| 
|   /* You can examine the output parameter to read the 
|    *  value you have just inserted. */ 
| end;

 (sempre si possano definire da ado...))
La SP che hai postato è un comando SQL (Create Procedure....).
Come tale, può essere sbattuto in un Execute e eseguito.
Come, ovviamente, anche un Alter Procedure.


 inserire nello script anche un Alter Procedure?
Bhe anche io uso gli script, solamente mettiamo che per qualche problema
non si aggiorna un exe o simile, una insert into/update non mi funziona piů
(dato che la stored si aspetta anche i nuovi campi). Anche se gli
eseguibili 99% vanno di pari passo, e se c'č qualche problema si reinvia
l'eseguibile.
Oppure clienti che hanno versioni minimizzate del programma (che non
seguono lo sviluppo del base), a quel punto la SP si aspetta 50 campi in
input e io gliene posso dare max 10. A quel punto o c'č il modo di usare
una sorta di Optional, oppure sono "costretto" a portare avanti lo sviluppo
anche di questi progetti.
Comunque me le studierň bene per capire come funzionano :)
Tnx

 una sorta di Optional
Ovvio.
I parametri delle SP possono essere Optional, quindi tu puoi ribaltare 
la struttura del db, puoi modificare regole di business o regole di 
integrità, puoi mantenere aggiornati dati di consuntivo, ecc..., senza 
dover toccare l'eseguibile.
Considera che di server ne hai uno, di client ne puoi avere 100, di cui 
alcuni aggiornati e alcuni 'dimenticati' dal CED.
Scenario: trovi un bug che consente ad un client di inserire una 
porcheria nel db. Hai 100 client distribuiti, alcuni addirittura in 
esecuzione quindi non puoi neppure aggiornarli a caldo.
Soluzione 1: Modifichi la SP che esegue l'Insert, in modo da evitare 
che i valori tamarri siano inseriti. Poi, con comodo, rilasci la patch 
dell'Exe.
Soluzione 2: non hai SP, quindi fai telefonare a tutti gli operatori, 
supplicando di non fare doppio click su quella label. Poi, di corsa 
perchè la gente sta lavorando e il cliente è incazzato e ti vuole fare 
causa, cerchi il bug e modifichi e ricompili e non hai tempo di testare 
e speri e hai fatto un nuovo bug e...


 e speri e hai fatto un nuovo bug e...
E questo è il mio pane quotidiano ^_^