滑稽,但我剛好與這個被打:
create trigger dbo.Things_Log on dbo.Things after Delete, Insert, Update as
declare @Now as DateTimeOffset = SysDateTimeOffset();
-- Determine the action that fired the trigger.
declare @Action VarChar(6) =
case
when exists (select 42 from inserted) and exists (select 42 from deleted) then 'update'
when exists (select 42 from inserted) then 'insert'
when exists (select 42 from deleted) then 'delete'
else NULL end;
if @Action is NULL
return;
-- Assign a unique value to group the log rows for this trigger firing.
declare @TriggerId as Int;
update TriggerIds
set @TriggerId = TriggerId += 1;
-- Log the data.
if @Action in ('delete', 'update')
insert into ThingsLog
select @Action + '-deleted', @TriggerId, @Now, dbo.OriginalLoginName(), ThingId, ThingName
from deleted;
if @Action in ('insert', 'update')
insert into ThingsLog
select @Action + '-inserted', @TriggerId, @Now, dbo.OriginalLoginName(), ThingId, ThingName
from inserted;
go
-- Logging triggers should always fire last.
execute sp_settriggerorder @triggername = 'dbo.Things_Log', @order = 'Last', @stmttype = 'DELETE';
execute sp_settriggerorder @triggername = 'dbo.Things_Log', @order = 'Last', @stmttype = 'INSERT';
execute sp_settriggerorder @triggername = 'dbo.Things_Log', @order = 'Last', @stmttype = 'UPDATE';
go
上下文:
create function [dbo].[OriginalLoginName]()
returns NVarChar(128)
as
begin
-- Returns the original login used to create the current session: Domain\username or sqlusername.
-- This function is not affected by impersonation.
-- Requires granting execute access to [public] and represents a diminutive security hole.
declare @Result as NVarChar(128);
select @Result = original_login_name
from sys.dm_exec_sessions
where session_id = @@SPID;
return @Result;
end;
go
CREATE TABLE [dbo].[Things](
[ThingId] [int] IDENTITY(1,1) NOT NULL,
[ThingName] [varchar](16) NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[ThingsLog](
[ThingsLogId] [int] IDENTITY(1,1) NOT NULL,
[Action] [varchar](16) NOT NULL,
[TriggerId] [int] NOT NULL,
[TriggerTime] [datetimeoffset](7) NOT NULL,
[OriginalLoginName] [nvarchar](128) NOT NULL,
[ThingId] [int] NOT NULL,
[ThingName] [varchar](16) NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[TriggerIds](
[TriggerId] [int] NULL
) ON [PRIMARY]
GO
insert into dbo.TriggerIds (TriggerId) values (0);
登錄觸發器應配置最後開火。這可以防止可能隨後由其他觸發器回滾的日誌記錄操作。對於獎勵積分,查詢可以報告未配置最後射擊記錄觸發(假設你有一個一致的命名約定,如TableName_Log,爲觸發器):
select PO.name as TableName, O.name as TriggerName, TE.type_desc,
case when O.name like PO.name + '_Log%' then 1 else 0 end as LoggingTrigger,
case when O.name like PO.name + '_Log%' and TE.is_last = 0 then 1 else 0 end as Misconfigured,
'' as [-], PO.type_desc as TableType, T.is_disabled, TE.is_first, TE.is_last, T.is_instead_of_trigger
from sys.objects as O inner join
sys.triggers as T on T.object_id = O.object_id inner join
sys.objects as PO on PO.object_id = T.parent_id inner join
sys.trigger_events as TE on TE.object_id = T.object_id
where
PO.type = 'U' and -- User table.
T.parent_class = 1 and -- Object or column trigger.
T.is_disabled = 0 and -- Is not disabled.
T.is_instead_of_trigger = 0 -- AFTER, not INSTEAD OF, trigger.
order by PO.name, O.name, TE.type_desc;
它可以在存儲過程中被合併這可以糾正記錄觸發器的觸發順序。