2015-01-07 6 views
5

Come faccio a riscrivere questo trigger di aggiornamento senza utilizzare molte variabili?Ho bisogno di ottimizzare il mio primo trigger di aggiornamento T-SQL

Ho scritto il mio primo trigger SQL Server e funziona bene, ma penso che ci sia una soluzione più semplice.

Se si modifica almeno una delle 5 colonne, scrivo due nuove righe in un'altra tabella. riga 1 = vecchio Fahrer (= Driver) e vecchio dispodate e aggiornamento riga 2 = nuovo Fahrer e nuovo dispodato e aggiornatounetime La mia soluzione è solo una copia del trigger foxpro, ma ci devono essere soluzioni più semplici in T -SQL per verificare se una colonna è stata modificata.

ALTER TRIGGER [dbo].[MyTrigger] 
ON [dbo].[tbldisposaetze] 
AFTER UPDATE 
AS 
SET NOCOUNT ON; 
/*SET XACT_ABORT ON 
SET ARITHABORT ON 
*/ 
DECLARE @oldfahrer varchar(10) 
DECLARE @oldbus varchar(10) 
DECLARE @olddispodat date 
DECLARE @oldvzeit decimal(4,0) 
DECLARE @oldbzeit decimal(4,0) 
DECLARE @oldbeschreibk varchar(255) 

DECLARE @newfahrer varchar(10) 
DECLARE @newbus varchar(10) 
DECLARE @newdispodat date 
DECLARE @newvzeit decimal(4,0) 
DECLARE @newbzeit decimal(4,0) 
DECLARE @newbeschreibk varchar(255) 

    SELECT @oldfahrer = fahrer,@oldbeschreibk=beschreibk,@oldbus=bus,@oldbzeit=bzeit,@olddispodat=dispodat,@oldvzeit=vzeit 
     FROM DELETED D 
    SELECT @newfahrer = fahrer,@newbeschreibk=beschreibk,@newbus=bus,@newbzeit=bzeit,@newdispodat=dispodat,@newvzeit=vzeit 
     FROM inserted I 

if @oldbeschreibk <> @newbeschreibk or @oldbus <> @newbus or @oldbzeit <> @newbzeit or @oldfahrer <> @newfahrer or @oldvzeit <> @newvzeit 
begin 
    IF (SELECT COUNT(*) FROM tbldispofahrer where [email protected] and [email protected]) > 0 
    update tbldispofahrer set laenderung = GETDATE() where [email protected] and [email protected] 
    else 
    INSERT into tbldispofahrer (fahrer,dispodat,laenderung) VALUES (@oldfahrer,@olddispodat,getdate()) 

    IF (SELECT COUNT(*) FROM tbldispofahrer where [email protected] and [email protected]) > 0 
    update tbldispofahrer set laenderung = GETDATE() where [email protected] and [email protected] 
    else 
    INSERT into tbldispofahrer (fahrer,dispodat,laenderung) VALUES (@newfahrer,@newdispodat,getdate()) 
end 
+1

Ok prima non si dovrebbe usare le variabili come questo a tutti !! Mai in qualsiasi trigger. Le tabelle cancellate e inserite possono contenere più record e DEVI scrivere il codice per considerarlo. – HLGEM

+0

Il tuo trigger ha ** MAJOR ** difetto in quanto sembri presumere che verrà chiamato ** una volta per riga ** - che è ** non ** il caso. Il trigger scatterà ** una volta per istruzione **, quindi se le tue istruzioni "UPDATE" riguardano 25 righe, il trigger verrà attivato ** una volta **, ma poi "Inserito" e "Eliminato" contengono ciascuna 25 righe . Quale di quelle 25 righe sceglierà il codice 'SELECT' ?? È non deterministico. È necessario riscrivere il trigger per tenerne conto! –

+0

Qual è la colonna chiave principale nella tabella 'tbldispofahrer'. –

risposta

4

Suppongo che tu abbia SQL Server 2008 o versione successiva. Puoi fare tutto questo in un'unica istruzione senza alcuna variabile.

Invece di fare tutto il lavoro per ottenere prima le variabili e vedere se non corrispondono, è possibile farlo facilmente come parte della clausola where. Come si è detto nei commenti, è possibile avere più righe come parte dell'inserimento e dell'eliminazione. Per assicurarti di lavorare con la stessa riga aggiornata, devi abbinare la chiave primaria.

Per inserire o aggiornare la riga, sto utilizzando un'istruzione MERGE. La fonte dell'unione è un'unione con la clausola where in alto, la tabella in alto nel sindacato ha il vecchio fahrer, e il bottom ha il nuovo farher. Proprio come i tuoi IF interiori, le righe esistenti sono abbinate su farter e dispodat, e inserite o aggiornate in modo appropriato.

Una cosa che ho notato è che nel tuo esempio newfahrer e oldfahrer potrebbero essere esattamente uguali, in modo che si verifichi un solo inserimento o aggiornamento (ad esempio se solo bzeit era diverso). L'unione dovrebbe impedire che i dati duplicati provino a essere inseriti. Credo che fusione si errore se ci fosse.

MERGE tbldispofahrer AS tgt 
USING (
    SELECT d.farher, d.dispodat, GETDATE() [laenderung] 
    INNER JOIN inserted i ON i.PrimaryKey = d.PrimaryKey 
     AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreik ...) 
    UNION 
    SELECT i.farher, i.dispodat, GETDATE() [laenderung] 
    INNER JOIN inserted i ON i.PrimaryKey = d.PrimaryKey 
     AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreik ...) 
) AS src (farher, dispodat, laenderung) 
ON tgt.farher = src.farher AND tgt.dispodat = src.dispodat 
WHEN MATCHED THEN UPDATE SET 
    laenderung = GETDATE() 
WHEN NOT MATCHED THEN 
    INSERT (fahrer,dispodat,laenderung) 
    VALUES (src.fahrer, src.dispodat, src.laenderung) 
1

Nella risposta di Daniel ci sono stati alcuni piccoli errori di sintassi. Il seguente codice sta funzionando benissimo:

MERGE tbldispofahrer AS tgt 
 
USING (
 
    SELECT d.fahrer, d.dispodat, GETDATE() [laenderung] from deleted d 
 
    INNER JOIN inserted i ON i.satznr = d.satznr 
 
     AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreibk or i.bus <> d.bus or i.bzeit <> d.bzeit or i.vzeit <> d.vzeit) 
 
    UNION 
 
    SELECT i.fahrer, i.dispodat, GETDATE() [laenderung] from inserted i 
 
    INNER JOIN deleted d ON i.satznr = d.satznr 
 
     AND (i.fahrer <> d.fahrer OR i.beschreibk <> d.beschreibk or i.bus <> d.bus or i.bzeit <> d.bzeit or i.vzeit <> d.vzeit) 
 
) AS src (fahrer, dispodat, laenderung) 
 
ON tgt.fahrer = src.fahrer AND tgt.dispodat = src.dispodat 
 
WHEN MATCHED THEN UPDATE SET 
 
    laenderung = GETDATE() 
 
WHEN NOT MATCHED THEN 
 
    INSERT (fahrer,dispodat,laenderung) 
 
    VALUES (src.fahrer, src.dispodat, src.laenderung);

Problemi correlati