Ich mag Lösungen, die "Informatik elegant" sind. Meine Lösung hier trifft die Pseudotabellen [eingefügt] und [gelöscht] jeweils einmal, um ihren Status zu erhalten, und fügt das Ergebnis in eine Bitmap-Variable ein. Dann kann jede mögliche Kombination von INSERT, UPDATE und DELETE während des gesamten Triggers mit effizienten binären Auswertungen leicht getestet werden (mit Ausnahme der unwahrscheinlichen Kombination INSERT oder DELETE).
Es wird davon ausgegangen, dass es keine Rolle spielt, wie die DML-Anweisung lautete, wenn keine Zeilen geändert wurden (was die überwiegende Mehrheit der Fälle erfüllen sollte). Es ist zwar nicht so vollständig wie die Lösung von Roman Pekar, aber effizienter.
Mit diesem Ansatz haben wir die Möglichkeit, einen "FOR INSERT, UPDATE, DELETE" -Trigger pro Tabelle zu verwenden, wodurch wir A) die vollständige Kontrolle über die Aktionsreihenfolge und b) eine Codeimplementierung pro für mehrere Aktionen anwendbarer Aktion erhalten. (Natürlich hat jedes Implementierungsmodell seine Vor- und Nachteile. Sie müssen Ihre Systeme individuell bewerten, um herauszufinden, was wirklich am besten funktioniert.)
Beachten Sie, dass die Anweisungen "existiert (wählen Sie * aus" eingefügt / gelöscht ")" sehr effizient sind, da kein Festplattenzugriff besteht ( https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6) -9ab0-a255cdf2904a ).
use tempdb
;
create table dbo.TrigAction (asdf int)
;
GO
create trigger dbo.TrigActionTrig
on dbo.TrigAction
for INSERT, UPDATE, DELETE
as
declare @Action tinyint
;
-- Create bit map in @Action using bitwise OR "|"
set @Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified
(select case when exists (select * from inserted) then 1 else 0 end)
| (select case when exists (select * from deleted ) then 2 else 0 end))
;
-- 21 <- Binary bit values
-- 00 -> No Rows Modified
-- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
-- 11 -> UPDATE <
-- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set
raiserror(N'@Action = %d', 10, 1, @Action) with nowait
;
if (@Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
;
-- do things for INSERT only
if (@Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
;
-- do things for UPDATE only
if (@Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
;
-- do things for DELETE only
if (@Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
;
-- do things for INSERT or UPDATE
if (@Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
;
-- do things for UPDATE or DELETE
if (@Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
;
-- do things for INSERT or DELETE (unlikely)
if (@Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
-- if already "return" on @Action = 0, then use @Action < 3 for INSERT or DELETE
;
GO
set nocount on;
raiserror(N'
INSERT 0...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;
raiserror(N'
INSERT 3...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;
raiserror(N'
UPDATE 0...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;
raiserror(N'
UPDATE 3...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t;
raiserror(N'
DELETE 0...', 10, 1) with nowait;
delete t from dbo.TrigAction t where asdf < 0;
raiserror(N'
DELETE 3...', 10, 1) with nowait;
delete t from dbo.TrigAction t;
GO
drop table dbo.TrigAction
;
GO