Come far decidere direttamente allo script SQL se fare una INSERT o una UPDATE.
Quante volte vi sarà capitato di dover aggiornare una tabella con dei dati provenienti da una fonte esterna? Nella maggioranza dei casi, i dati da importare possono sia essere nuovi rispetto alla vostra tabella che essere degli aggiornamenti.
Scorrere con un cursore la tabella da importare e vedere record per record se è una novità o un aggiornamento è una scelta poco efficiente. Quale può essere allora una soluzione più performante?
Sfruttare la JOIN
La domanda necessaria da farsi è questa: in base a quale chiave riesco a capire se un record è una novità o un aggiornamento?
Una volta trovata la risposta, il meccanismo è semplice:
- si metteranno in JOIN le due tabelle (da importare ed esistente) relazionandole proprio con la chiave individuata
- la JOIN sarà una LEFT JOIN, con a sinistra la tabella da importare, e a destra quella già esistente
- come noto, la LEFT JOIN restituirà una serie di colonne NULL nella tabella di destra nel caso non ci siano corrispondenze: sfruttando questa caratteristica potremo quindi individuare quali sono i record già esistenti e quali invece sono nuovi
- ovviamente quelli nuovi saranno quelli con contenuto NULL, che sta a significare che i record della tabella di sinistra (da importare) NON sono già esistenti nella tabella di destra (esistente) e vanno quindi inseriti
- quelli invece non-NULL sono già esistenti, e quindi andranno aggiornati
- attenzione ad eseguire PRIMA la UPDATE e poi la INSERT; in caso contrario verranno aggiornati anche i record appena inseriti: i dati non vengono assolutamente danneggiati, ma sicuramente ci sarà una perdita di tempo
Esempio pratico
Un esempio aiuterà a comprendere più facilmente il meccanismo.
Immaginiamo di dover aggiornare una tabella di Dati Anagrafici con dei dati che ci vengono inviati periodicamente da un corrispondente; in questo caso, la chiave identificativa (univoca) sarà la Partita IVA.
Per comodità, avremo già importato i dati del nostro corrispondente in una tabella temporanea; i nomi delle colonne saranno gli stessi.
Impostiamo quindi la JOIN:
-- TS=TableSource, TT=TableTarget SELECT TS.Descrizione, TS.PartitaIVA, TT.Descrizione, TT.PartitaIVA FROM #tmpAnag TS LEFT JOIN ANAGRAFICHE TT ON TS.PartitaIVA=TT.PartitaIVA
Quando eseguiremo questa query, vederemo elencate delle corrispondenze esatte nel caso di record da aggiornare, mentre invece noteremo TT.Descrizione e TT.PartitaIVA a NULL nel caso di novità.
Sfrutteremo quindi la JOIN di riferimento per impostare prima una UPDATE…FROM…JOIN per fare gli aggiornamenti, poi una INSERT…SELECT…JOIN per fare gli inserimenti.
UPDATE
-- TS=TableSource, TT=TableTarget UPDATE ANAGRAFICHE SET Denominazione=TS.Denominazione, Indirizzo=TS.Indirizzo, CAP=TS.CAP, Localita=TS.Localita, PartitaIVA=TS.PartitaIVA FROM #tmpAnag TS LEFT JOIN ANAGRAFICHE TT ON TS.PartitaIVA=TT.PartitaIVA -- fa correttamente la JOIN? Quindi c'è GIA'! ---> UPDATE
INSERT
-- TS=TableSource, TT=TableTarget INSERT INTO ANAGRAFICHE (Denominazione, Indirizzo, CAP, Localita, PartitaIVA) SELECT TS.Denominazione, TS.Indirizzo, TS.CAP, TS.Localita, TS.PartitaIVA FROM #tmpAnag TS LEFT JOIN ANAGRAFICHE TT ON TS.PartitaIVA=TT.PartitaIVA WHERE TT.PartitaIVA IS NULL -- non fa la JOIN? Quindi NON c'è! ---> INSERT
Grande!!!! Proprio quello che cercavo!!