SQL Trigger - Cancellato o aggiornato? o forse qualcosa d'altro?
-
26-10-2019 - |
Domanda
Sto cercando di capire che ho bisogno di usare qui:. Eliminato, inserito o aggiornato
in fondo.
Ho bisogno di scrivere alcuni dati nella tabella storia, quando la tabella principale è aggiornato, e solo se lo stato cambia da qualcosa a uno in sospeso o attivo.
Questo è quello che ho adesso:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE AS
DECLARE @statusOldValue char(1)
DECLARE @statusNewValue char(1)
SELECT @statusOldValue = statusCode FROM deleted
SELECT @statusNewValue= statusCode FROM updated
IF (@statusOldValue <> @statusNewValue) AND
(@statusOldValue = 'P' or @statusOldValue = 'A')
BEGIN TRY
INSERT * INTO tblHistoryTable)
select * from [DELETED]
così voglio i nuovi dati di rimanere nella tabella principale, la tabella la storia per essere aggiornato con ciò che viene sovrascritto ... In questo momento è solo copie le stesse informazioni sopra. così dopo l'aggiornamento, entrambi i miei tabelle hanno gli stessi dati.
Soluzione
È necessario utilizzare le tabelle sia il inserted
e deleted
insieme per verificare la presenza di record che:
1. esisteva già (per verificare che non è un inserto)
2. esiste ancora (per controllare che non è una cancellazione)
3. Il campo Stato cambiato
È inoltre necessario assicurarsi che fare che in un approccio basato insieme, come per la risposta di marc_s, i trigger non sono processi singolo record.
INSERT INTO
tblHistoryTable
SELECT
deleted.*
FROM
inserted
INNER JOIN
deleted
ON inserted.PrimaryKey = deleted.PrimaryKey
WHERE
inserted.StatusCode <> deleted.StatusCode
AND (inserted.StatusCode = 'P' OR inserted.StatusCode = 'A')
- = inserito i nuovi valori
- soppresso = i vecchi valori
Altri suggerimenti
Non ci sono solo le tabelle pseudo Inserted
e Deleted
- non c'è Updated
.
Per un UPDATE
, Inserted
contiene i nuovi valori (dopo l'aggiornamento), mentre Deleted
contiene i vecchi valori prima dell'aggiornamento.
Anche essere consapevoli che i trigger è sparato una volta per partita ??strong> - non una sola volta per ogni riga. Così entrambe le tabelle pseudo saranno potenzialmente contengono più righe ! Non dare per scontato una singola riga per poi assegnarlo a una variabile - questo
SELECT @statusOldValue = statusCode FROM deleted
SELECT @statusNewValue= statusCode FROM updated
non riuscirà se si dispone di più righe! Hai bisogno di scrivere i trigger in modo tale che lavorano con più righe in Inserted
e Deleted
!
Aggiornamento: Sì - ci un modo molto migliore per scrivere questo:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE
AS
INSERT INTO dbo.tblHistoryTable(Col1, Col2, Col3, ...., ColN)
SELECT Col1, COl2, Col3, ..... ColN
FROM Deleted d
INNER JOIN Inserted i ON i.PrimaryKey = d.PrimaryKey
WHERE i.statusCode <> d.statusCode
AND d.statusCode IN ('A', 'P')
In sostanza:
-
specificare esplicitamente le colonne che si desidera inserire - sia nella dichiarazione
INSERT
così come la dichiarazioneSELECT
il recupero dei dati da inserire - per evitare sorprese -
Crea un
INNER JOIN
traInserted
eDeleted
pseudo-tabelle per ottenere tutte le righe che sono stati aggiornati -
specificare tutte le altre condizioni (diversi codici di stato, ecc) nella clausola
WHERE
delSELECT
Questa soluzione funziona per i lotti di file in fase di aggiornamento - non mancherà su un aggiornamento multi-fila ....
Non v'è alcun tavolo updated
, siete alla ricerca di inserted
.