Trovare il new id da inserire in una tabella da vb

martedì 08 luglio 2008 - 14.19

Lucifel Profilo | Junior Member

Ciao a tutti
mi sono scontrato in un problema assai problematico, nel senso che ho 2 problemi legati a una query.

Ho un db in sql server 2005 express edition. Ho 2 tabelle di questo tipo:

TABELLA 1
Id
Campo1
Campo2
DataStart
DataEnd

TABELLA 2
Id
Campo1
Campo2
DataStart
DataEnd

Dove la chiave è una chiave composta da Id e DataStart.

E dove Tabella 2 è legata a Tabella 1 da una relazione 1 a n.

Detto ciò il problema sta qua:
Devo fare in vb una query di insert e una di update con queste caratteristiche:
L'insert deve creare ovviamente un nuovo record in Tabella 1 e n nuovi record in tabella 2
L'update deve modificare il campo DataEnd delle 2 tabelle e fare un nuovo insert con i dati modificati.

Il problema però qua si pone sulla chiave. Mi spiego: se io metto autoincrement l'id della tabella 1 non posso fare
l'update corretto in quanto l'insert successivo non deve creare un nuovo id, ma tenere quello che ho già inserito.
Se non metto autoincrement questo problema si risolve, ma come faccio ad ottenere l'id da inserire quando faccio
un nuovo insert? Cioè dovrei fare una query per trovare l'ultimo id inserito nella tabella e poi fare +1, però come
faccio a gestire la concorrenza sulla tabella. Cioè, mentre io ho estratto l'ultimo id e sto per fare l'insert (ma non è
ancora stata fatta) un altro utente potrebbe rileggere lo stesso id.

C'è qualche soluzione a questo problema?
Se non mi sono spiegato bene basta chiedere.

Grazie a tutti in anticipo

Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

Stroke Profilo | Junior Member

In questo Thread http://www.dotnethell.it/forum/messages.aspx?ThreadID=23707 c'è la risposta.
ciao
Furio
http://www.opsi.ws

Lucifel Profilo | Junior Member

Grazie, ma veramente non è quello che mi serve.
Io devo avere un codice PRIMA di fare l'insert e devo essere sicuro che questo codice sia univoco per tutti gli utenti dell'applicazione.

Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

alexmed Profilo | Guru

Utilizza "SCOPE_IDENTITY()"

Dim conn As New SqlClient.SqlConnection("Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\myDatabase.mdf;Integrated
Security=True;User Instance=True")

conn.Open()

Dim sqlCmd As SqlClient.SqlCommand = New SqlClient.SqlCommand("INSERT INTO nome_tabella () " & _
"VALUES (); SELECT @Identity = SCOPE_IDENTITY();", conn)


Dim idParm As SqlClient.SqlParameter = sqlCmd.Parameters.Add("@Identity", SqlDbType.Int)
idParm.Direction = ParameterDirection.Output

sqlCmd.ExecuteNonQuery()

Dim newID As Integer = CType(idParm.Value, Integer) ' Qui recuperi il valore che hai appena inserito

conn.Close()

Me.myTableAdapter.Insert(newID) ' Qui lo usi per inserire il nuovo ID nella seconda tabella


Tutto chiaro?

http://msdn.microsoft.com/it-it/library/ms190315.aspx

Ciao

Stroke Profilo | Junior Member

Ti abbiamo risposto in due la stessa cosa, evidentemente non è chiaro ciò che vuoi ottente.
Il rapporto 1 a n tra le due tabelle da quali campi è legato?

Secondo me devi usare l'autoincrement sulla tabella 1 e inserire un campo di riferimento nella tabella 2 all'id della tabella 1.
il problema della concorrenza lo elimini inserendo tutte le tue query in una unica store procedure tra un begin e un end in modo che la sp effettua tutte le operazioni consecutivamente oppure se c'è un errore non ne effettua nemmeno una e torna come all'origine.
In questo modo in un'unica store procedure fai update della dataend filtrando il campo ID della tabella 1 e il campo "ID della Tab1" nella Tab2, poi effettui l'insert recuperi il nuovo id e lo utilizzi subito per gli insert nella tabella 2, una chiamata successiva anche di pochi secondi non potrà mai utilizzare lo stesso id.
Altrimenti non ho capito cosa vuoi fare.
ciao
Furio
http://www.opsi.ws

Lucifel Profilo | Junior Member

Perché dai per scontato che usi le store procedure?
Io ho un codice vb che scrive la query e poi fa l'excecute e tutte le operazioni le ho messe in una transazione.

Le tabelle sono:
T1
Id*, dateStart*, dateEnd, c1, c2

T2
Id*, dateStart*, dateEnd, c3*, c4

(i campi con * sono le chiavi primarie delle tabelle)

I dati inseriti sono:

T1
1, 1/1/2008, (null), 'A', 'B'

T2
1, 1/1/2008, (null), 1/1/2008, 'C'
1, 1/1/2008, (null), 2/1/2008, 'D'

Non posso mettere l'autoincrement su id di T1 perché il mio update non deve modificare il campo ma deve mettere un campo di validità dateEnd con il valore e inserire un nuovo record. Es:

T1
1, 1/1/2008, 10/1/2008, 'A', 'B'
1, 10/1/2008, (null), 'F', 'G'

T2
1, 1/1/2008, 10/1/2008, 1/1/2008, 'C'
1, 1/1/2008, 10/1/2008, 2/1/2008, 'D'
1, 10/1/2008, (null), 1/1/2008, 'E'
1, 10/1/2008, (null), 2/1/2008, 'H'

Dopo l'update devo ottenere una cosa del genere. Nel caso in cui abbia l'auto increment non posso rimettere 1 sull'id di T1, ma avrei 2, e mi va a cambiare tutta la logica con cui queste 2 tabelle sono unite al resto del db.

Spero di essere stato chiaro adesso.

Quindi la domanda è: Nel caso di un nuovo insert (quindi non un update perché in quel caso l'id ce l'ho già) io devo avere un nuovo id da inserire (quindi vorrei 2), quindi se faccio una query con 'SELECT Max(id) FROM T1' e poi faccio +1 ho problemi di concorrenza peché se un altro utente fa la stessa operazione troverei il medesimo id per 2 record diversi da inserire.

Spero di essere stato chiaro.

Grazie comunque per le risposte.

Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

alexmed Profilo | Guru

Ciao Lucifel,
Solo un chiarimento

La tua prima insert è:

T1
1, 1/1/2008, (null), 'A', 'B'
T2
1, 1/1/2008, (null), 1/1/2008, 'C'
1, 1/1/2008, (null), 2/1/2008, 'D'

La seconda insert dovrà essere:

I dati inseriti sono:

T1
2, 1/1/2008, (null), 'A', 'B'
T2
2, 1/1/2008, (null), 1/1/2008, 'C'
2, 1/1/2008, (null), 2/1/2008, 'D'

Oppure:

T1
2, 1/1/2008, (null), 'E', 'F'
T2
2, 1/1/2008, (null), 1/1/2008, 'G'
2, 1/1/2008, (null), 2/1/2008, 'H'

??

Lucifel Profilo | Junior Member

Ciao
Hai ragione, non sono stato chiaro con l'esempio, ma stamattina ho una marea di robe da fare oltre a questo.

Allora la situazione di partenza é questa:

T1
1, 1/1/2008, (null), 'A', 'B'
T2
1, 1/1/2008, (null), 1/1/2008, 'C'
1, 1/1/2008, (null), 2/1/2008, 'D'

Poi voglio fare un update del valore A di T1 e metterlo a E in data 10/1/2008. Quindi la situazione deve diventare:

T1
1, 1/1/2008, 10/1/2008, 'A', 'B' ************************** E' Cancellato
1, 10/1/2008, (null), 'E', 'B' ************************** Ho messe E al posto di A
T2
1, 1/1/2008, 10/1/2008, 1/1/2008, 'C' ************************** E' Cancellato
1, 1/1/2008, 10/1/2008, 2/1/2008, 'D' ************************** E' Cancellato
1, 10/1/2008, (null), 1/1/2008, 'C' ************************** E' Rimasto invariato
1, 10/1/2008, (null), 2/1/2008, 'D' ************************** E' Rimasto invariato

Ora voglio inserire un nuovo record nella tabella T1 e 2 nuovi nella tabella T2

Quindi devo trovare il nuovo id (che sarà 2) e li voglio inserire in data 30/1/2008. La situazione quindi deve diventare:

T1
1, 1/1/2008, (null), 'A', 'B'
2, 30/1/2008, (null), 'K', 'I'

T2
1, 1/1/2008, (null), 1/1/2008, 'C'
1, 1/1/2008, (null), 2/1/2008, 'D'
2, 30/1/2008, (null), 1/1/2008, 'M'
2, 30/1/2008, (null), 2/1/2008, 'N'

NOTA: sono partito dalla situazione iniziale senza considerare il caso dell'update.

Spero di essere stato chiaro.

Mettendo insieme questi 2 casi, (cioè l'update che deve mantenere l'id precedente e l'insert che deve inserire un id nuovo) non posso usare l'id autoincrement sulla T1 (perché non funzionerebbe più l'update con lo stesso id) però per fare l'insert ho bisogno di un id prima di fare l'insert perché glielo devo passare all'INSERT. Qua come ho detto c'è il problema della concorrenza tra 2 persone che utilizzano il programma, nel senso che devo trovare il modo di bloccare le tabelle mentre un utente è in transazione per l'insert. Questo è quanto mi serve.

Per ora grazie.


Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

Stroke Profilo | Junior Member

Pesca il tuo id dentro la stessa query insert
insert into T1 (Id*, dateStart*, dateEnd, c1, c2) Value ((SELECT Max(id) FROM T1) +1,'Data',null,'A','B')
per l'aggiornamento di T2 togli il + 1
Furio
http://www.opsi.ws

Lucifel Profilo | Junior Member

>Pesca il tuo id dentro la stessa query insert
>insert into T1 (Id*, dateStart*, dateEnd, c1, c2) Value ((SELECT
>Max(id) FROM T1) +1,'Data',null,'A','B')

Posso fare una cosa del genere?????
Non mi dà errore?????????????????????

>per l'aggiornamento di T2 togli il + 1

Devo provare però così a intuito non credo sia quello che mi serve, perché potrebbe essere che quando rifaccio la query per inserire in T2 devo rifare la query e mentre lo faccio potrebbe essere che un altro utente abbia inserito un altro record in T1 così io leggo l'id sbagliato.

Cmq provo e poi ti dico.

Grazie intanto

Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

Stroke Profilo | Junior Member

beh ho dimenticato la s di values e ho lasciato gli asterischi sui campi perchè ho fatto un copia incolla dal tuo messaggio, ma la query è correttamente formulata.
Per T2 hai ragione, qualcuno potrebbe aver inserito un nuovo record, ecco perchè userei più volentieri una store procedure con dentro tutto. Nella coda del database finche non ha completato una sp non parte la successiva.
Oppure, dato che hai ancora disponibili i dati inseriti in t1 fai una query così
insert into T2 (Id, dateStart, dateEnd, c1, c2) Values ((SELECT top 1 id FROM T1 where Data = "LaDatatInserita" and c1="Il campoinserito") ,'Data',null,'A','B')
ciao
Furio
http://www.opsi.ws

Lucifel Profilo | Junior Member

Grazie per la risposta
Oggi che ho avuto un po' di tempo ho implementato questa query:

>insert into T1 (Id*, dateStart*, dateEnd, c1, c2) Value ((SELECT
>Max(id) FROM T1) +1,'Data',null,'A','B')

Purtroppo ha lanciato un'eccezione che fa:
In questo constesto sono consentite solo epressioni scalari e non sottoquery

Infatti immaginavo che non poteva funzionare.
Altre idee?


Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

Stroke Profilo | Junior Member

Che database usi?
Furio
http://www.opsi.ws

Lucifel Profilo | Junior Member

Per ora MS SQL Server 2005 Express Edition.

A breve però dovrà andare bene per SQL Server 2000
A lungo dovrà andare bene per ORACLE

Cmq mi basterebbe che per ora andasse bene per SQL 2005.

Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------

Stroke Profilo | Junior Member

Sqlseerver 2005 supporta tranquillamente le subquery, non capisco perchè non debba funzionare, uso subquery da sempre in sqlserver2000/2005.
Probabilmente se fossimo postati nella stanza dei database Lorenzo Benaglia ci avrebbe già risposto la soluzione.
L'utilizzo di una sp ti semplificherebbe la vita, ma solo perchè dividi la query e la subquery all'interno della sp.
Non capisco qual'è il contesto che impedisca la subquery, perchè, ripero, sqlserver supporta tranquillamente le subquery.

Furio
http://www.opsi.ws

Lucifel Profilo | Junior Member

>Sqlseerver 2005 supporta tranquillamente le subquery, non capisco
>perchè non debba funzionare, uso subquery da sempre in sqlserver2000/2005.
>Probabilmente se fossimo postati nella stanza dei database Lorenzo
>Benaglia ci avrebbe già risposto la soluzione.
>L'utilizzo di una sp ti semplificherebbe la vita, ma solo perchè
>dividi la query e la subquery all'interno della sp.
>Non capisco qual'è il contesto che impedisca la subquery, perchè,
>ripero, sqlserver supporta tranquillamente le subquery.

Non so che risponderti. L'eccezione me l'ha generata e quello è il motivo.
A parte questo non posso usare store procedure perché questa è solo una piccola parte del sistema e se comincio ad inserire sp qua dovrei (per coerenza) inserirle anche per tutte le altre parti del sistema... e siceramente non posso prendere questa decisione da solo, anche perché dovrei rifare in pratica metà progetto.

Cmq riproverò lunedì.
Intanto grazie per il consiglio.
Ti saprò dire come spero di aver risolto...


Diego
-----------------------------------
Avanti sempre e comunque!
-----------------------------------
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5