Newsgroup: it.comp.lang.delphi
Titolo: Inserimento nuovo record in DB: come procedere

Salve a tutti, la mia domanda è un po' generica e non proprio su
Delphi, ma confido nella vostra "bontà" :-)
Allora vorrei sapere e capire quale è la strada migliore per inserire
un record in una tabella di un db (oracle 9 nel mio caso): per fare un
esempio ho una persona, la chiave è il codice fiscale. Ottenuti i suoi
dati dall'applicazione devo inserirla nel db, se però non è già
presente: è meglio (in termini di velocità) sfruttare il vincolo
della chiave per cui avrò un eccezione se esiste già nel db, oppure
fare prima una select della chiave e, se il numero di risultati è 0,
inserirla poi? 
Grazie dell'aiuto
Ciao ciao
Matteo

io farei il check lato app appena l'utente ha inserito il codice
fiscale.
Credo che si inkazzerebbe alquanto se, dopo aver inserito tutti i dati
scopre che esiste gia, sopratutto se i dati da inserire sono tanti..
AS

 inserirla poi?
Secondo me il modo migliore è quello di sfruttare l'eccezione che ti 
viene sollevata quanto tenti di violare la chiave primaria, in qst caso 
il "codice fiscale". 
Se prima di inserire il record fai una select, il tempo di risposta della 
tua select può aumentare in relazione al numero di record che la tua 
query deve esaminare, mentre il meccanismo di integrità, che ha un db 
relazionale, può risultare molto comodo in qst caso.
Tutto IMHO!!!
Diego
--- posted by geoForum on 
http://www.delphiedintorni.it

Grazie mille Alberto, velocissima risposta!
Comunque il mio era un esempio, non è quello il mio caso. In realtà
non c'è una form da riempire e l'utente non si incazza (in realtà
sono pazienti con dati ricavati da immagini).
La questione era più "tecnica" sulla velocità di esecuzione della
procedura di inserimento e, se vogliamo, sulla correttezza di scrittura
del codice: è più elegante e veloce basarmi sull'eccezione causata
dal vincolo della chiave (però dovrei anche essere sicuro che
l'eccezione è per quel motivo e non per qualcos'altro sul db) oppure
è meglio prima fare una query per vedere se il record esiste già?
grazie

Scusa ma come facciamo a risponderti....dipende...
Se usi un Dataset potresti invocare il metodo FindKey per verificare se
il record esiste e successivamente utilizzare i metodi Edit se devi
editare e Insert se devi create.
Ma se usi ADO allora anzichè FindKey usi la Locate....
In qualsiasi caso devi verificare se il record esiste e dopodichè
aggiornarlo o inserirlo a meno che vuoi far sollevare un'eccezione e
poi gestirla anche se secondo me non è una buona soluzione.
Controdomanda: ma se non usi delphi perchè non chiedi a un NG che
parla solo di database così hai una risposta generica e poi se
utilizzi oracle di può tornare utile passare a
"comp.database.oracle"...
bye
Lorenzo

In realtà uso Delphi (versione 6) e i componenti ODBC Express per
accedere al database, dicevo così perchè la cosa mi sembrava generica
e riportabile a + linguaggi e DB.
Grazie della risposta, allora, come poi ho fatto, prima cerco e poi
inserisco senza eccezione (mi sembrava un po' + sporca).
ciao e grazie!!



Cosa succede se mentre cerchi e prima di inserire, qualcun altro
inserisce?
Qual'è la soluzione più sporca? ;-)
-- 
Ore 18.30: premo invio.

poi gestirla anche se secondo me non è una buona soluzione.
Locate vade retro! ;-)
Può andar bene per un database relazionale alla paradox, su un client
server è un'eresia pura (guarda il codice
TCustomADODataSet.LocateRecord).
Perché gestire un'eccezione non è una buona soluzione? Il post su una
chiave primaria e il successivo controllo di chiave duplicata è il
metodo più veloce e più pulito.
Ciao.


 metodo più veloce e più pulito.
Sono daccordo, e poi molti componenti come TTable, TADOTable, TIBTable 
hanno un evento "OnPostError" che può essere utile, io in passato l'ho 
usato e mi sono trovato bene.


Se lo dici tu...Io cmq preferisco fare ricerca e successivamente
inserire/aggiornare.
Chiaramente il tempo che passa tra il cercare e l'inserire deve essere
quasi nullo.
Utilizzo la Locate _solo_ con i componenti che non mi permettono di
utilizzare FindKey (se non ricordo male TAdoDataSet...ma non sono
sicuro perchè non ho Delphi sotto le mani oggi).
Per quanto riguarda l'eccezione come fai a distinguere in modo banale
un errore causato dal tuo insert che poi deve diventare update perchè
il record esiste già da un errore di "chiave duplicata" perchè c'è
un bug nel tuo codice ? quando te ne accorgi ?
L'eccezione provoca un carico sul DB che, a mio avviso, è più
dispendiosa di una FindKey+Insert/Edit oppure Locate+Insert/Edit.
Dimentichiamoci poi il discorso performances. Se devo fare 1000
findkey+insert/edit probabilmente devo scegliere una tecnica migliore
(stored procedures per esempio).
Questa è la mia idea. Cosa ne pensi ?
ciao
Lorenzo

Diciamo che per contesto e tipo di applicazione (monoutente) non può
esistere questa situazione e problema.
Grazie per i consigli, anche se mi state confondendo :-)
Esattamente (e qui chiedo un po' di "pappa pronta") come si fa quello
che dici nell'altro messaggio: "Il post su una chiave primaria e il
successivo controllo di chiave duplicata è il metodo più veloce e
più pulito. "?
Intendi fare una insert e controllare l'eccezione? Posso capire che
l'eccezione è proprio quella che mi interessa?
Ciao e grazie

Vedo che il thread è seguito :-)
La tecnica con stored procedures prevede di scrivere nel db una
procedura in cui al suo interno faccio direttamente la select e poi ,
nel caso di non esistenza della chiave, la insert? O devo procedere
diversamente?
Grazie ancora

Per quanto riguarda le stored procedure tieni presente che ogni DB ha
le sue peculiarità. indicativamente però tutti i DB supportano lo
standard SQL-92 (con Oracle è più complicata la faccenda).
Chiaramente stiamo uscendo dal discorso relativo Delphi e quindi
finiamo nell'OT.
In breve con le stored procedure i controlli di esistenza record
/insert/update sono all'ordine del giorno ma le stored servono
soprattutto per gli aggiornamenti massivi dove non è richiesta
assitenza da parte dell'utente (per esempio non puoi mostrare un
messaggio di errore e magari chiedere se si vuole procedere).
Sei sicuro che ti interessa ancora ? ...nel caso però il NG di delphi
non è molto indicato...
ciao
Lorenzo

Questa è la mia idea. Cosa ne pensi ?
Che sinceramente non capisco quale carico un post diretto su una
chiave primaria possa provocare (N mila volte inferiore a una banale
select).
Sul fatto che poi in molte situazioni le soluzioni migliori siano
altre non si discute, sono assolutamente d'accordo con te ;-)


 messaggio di errore e magari chiedere se si vuole procedere).
ma un db è LOGICA, non INTERFACCIA.
Non spetta alla stored procedure mostrare messaggi all'utente.
Puoi aggiungere alla stored procedure un parametro come out/var
opportunamente assegnato dalla stored procedure stessa del tipo:
0: record non esistente, è stato aggiunto alla tabella
-1: record gia esistente, non è stato aggiunto alla tabella.
Sara poi la app a dare un feedback all'utente in funzione del valore
che la proc gli passa nel parametro.
E' molto importante separare logica e interfaccia. Un codice del
genere:
procedure TQualcosa.FaiQualcosaSulDb();
begin
      try
        query.Fai();
      except
         ShowMessage(''errore')
      end;
end;
mischia logica (uso della query) con interfaccia (showmessage).
Si puo riscrivere cosi:
procedure TQualcosa.FaiQualcosaSulDb(var AStatus: integer; var
AErrorMsg: string);
begin
      try
        query.Fai();
      except
         AStatus := E.qualcosa;
         AErrorMsg := E.Message;.
      end;
end;
Sara poi la form che richiama il metodo a mostrare codici e messaggi di
errore.
AS

resto del msg...
Sono d'accordo con te forse mi sono spiegato male...

 SqlPlus...mi risulta essere un po diverso...
SqlPus è un programma un po scomodo, si.
Ma EA, pur essendo una vera "lota" (trad. letterale dal napoletano:
fango, sionimo di merda...), almeno questo te lo fa fare.
Lo so xche l'ho fatto.
AS