Perché FOR Trigger non viene eseguito prima dell'azione?
-
03-07-2019 - |
Domanda
Sto cercando di scrivere un trigger su una tabella per evitare l'inserimento di due nomi che non sono contrassegnati come IsDeleted. Ma la prima parte della selezione contiene quella inserita e quindi la condizione è sempre vera. Ho pensato che l'uso della parola chiave FOR causa l'esecuzione del trigger prima di INSERTION ma in questo caso la riga inserita è già nella tabella. Sbaglio o è così che funzionano tutti i trigger FOR?
ALTER TRIGGER TriggerName
ON MyTable
FOR INSERT, UPDATE
AS
BEGIN
If exist (select [Name] From MyTable WHERE IsDeleted = 0 AND [Name] in (SELECT [Name] FROM INSERTED)
BEGIN
RAISERROR ('ERROR Description', 16, 1);
Rollback;
END
END
Soluzione
FOR viene eseguito dopo la modifica dei dati, INSTEAD OF è ciò che penso tu stia cercando.
EDIT: come affermato da altri, INSTEAD OF viene eseguito invece dei dati che si stanno modificando, pertanto è necessario inserire i dati se sono validi, anziché interrompere l'inserimento se non è valido.
Leggi questa domanda per una spiegazione molto più dettagliata dei tipi di trigger.
SQL Server " AFTER INSERT " il trigger non vede la riga appena inserita
Altri suggerimenti
FOR è uguale a AFTER. se vuoi " simulare " PRIMA del trigger, utilizzare INSTEAD OF, avvertenza, non è esattamente quello che ci si aspetterebbe dal corretto trigger PRIMA, ovvero se non si fornisce l'azione INSTEAD necessaria, i dati inseriti / aggiornati potrebbero andare persi / ignorati.
MSSQL non ha PRIMA l'attivazione.
Per SQL Server, FOR esegue DOPO l'SQL che lo ha attivato.
Da: http://msdn.microsoft.com/en-us/library/ms189799. aspx
FOR | DOPO
DOPO specifica che il trigger DML viene attivato solo quando tutte le operazioni specificato nell'innesco di SQL dichiarazione eseguita correttamente. Tutte le azioni a cascata referenziali e anche i controlli dei vincoli devono avere esito positivo prima che questo grilletto si attivi.
DOPO è l'impostazione predefinita quando FOR è il è stata specificata solo la parola chiave.
DOPO si innesca non può essere definito nelle viste.
Ultimamente ho riscontrato un problema simile di recente e ho trovato un modo fantastico per gestirlo. Avevo una tabella che poteva avere più righe per un ID, ma solo UNA di esse poteva essere contrassegnata come primaria.
In SQL Server 2008, sarai in grado di creare un indice univoco parziale simile a questo:
create unique index IX on MyTable(name) where isDeleted = 0;
Tuttavia, puoi eseguirlo con un po 'più di lavoro in SQL Server 2005. Il trucco è creare una vista che mostri solo le righe che non sono state cancellate, e quindi creare un indice cluster univoco su di esso:
create view MyTableNotDeleted_vw
with schema_binding /* Must be schema bound to create an indexed view */
as
select name
from dbo.MyTable /* Have to use dbo. for schema bound views */
where isDeleted = 0;
GO
create unique clustered index IX on MyTableNotDeleted_vw ( name );
Questo creerà effettivamente un vincolo unico che riguarda solo le righe che non sono ancora state eliminate e probabilmente funzionerà meglio di un trigger personalizzato!