确实,在MSSQL中没有“before triggers”。但是,您仍然可以通过同时使用“inserted”和“deleted”表来跟踪对表进行的更改。当更新引发触发器时,“inserted”表存储新值,“deleted”表存储旧值。有了这些信息,您就可以相对容易地模拟“before trigger”的行为。
不能确定这是否适用于 SQL Server Express,但是即使在触发器在更新之后执行时,您仍然可以访问“之前”的数据。必须从在表更改时临时创建的deleted或inserted表中读取数据。这基本上是@Stamen所说的,但我仍需要进一步探索才能理解那个有帮助的答案。
deleted 表存储 DELETE 和 UPDATE 语句期间受影响行的副本。在执行 DELETE 或 UPDATE 语句期间,将从触发器表中删除行并转移到 deleted 表中...
inserted 表在 INSERT 和 UPDATE 语句期间存储受影响行的副本。在插入或更新事务期间,新行会添加到 inserted 表和触发器表中...
因此,您可以创建触发器从其中一个表中读取数据,例如:
CREATE TRIGGER <TriggerName> ON <TableName>
AFTER UPDATE
AS
BEGIN
INSERT INTO <HistoryTable> ( <columns...>, DateChanged )
SELECT <columns...>, getdate()
FROM deleted;
END;
我的示例基于这里的示例:
T-SQL只支持AFTER和INSTEAD OF触发器,不像其他一些关系型数据库管理系统那样有BEFORE触发器。
我认为您需要使用一个INSTEAD OF触发器。
在SQL Server中,所有“普通”触发器都是“AFTER…”触发器。没有“BEFORE…”触发器。
如果想在更新之前执行某些操作,请查看INSTEAD OF UPDATE Triggers。
在SQL Server中执行BEFORE UPDATE
,我使用一个技巧。我对记录进行虚假更新(UPDATE Table SET Field = Field
),以此方式获得记录的先前图像。
更新或删除的值存储在 DELETED 中。我们可以通过触发器中的以下方法获取它
完整示例:
CREATE TRIGGER PRODUCT_UPDATE ON PRODUCTS
FOR UPDATE
AS
BEGIN
DECLARE @PRODUCT_NAME_OLD VARCHAR(100)
DECLARE @PRODUCT_NAME_NEW VARCHAR(100)
SELECT @PRODUCT_NAME_OLD = product_name from DELETED
SELECT @PRODUCT_NAME_NEW = product_name from INSERTED
END
完整示例:
CREATE TRIGGER [dbo].[trig_020_Original_010_010_Gamechanger]
ON [dbo].[T_Original]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @Old_Gamechanger int;
DECLARE @New_Gamechanger int;
-- Insert statements for trigger here
SELECT @Old_Gamechanger = Gamechanger from DELETED;
SELECT @New_Gamechanger = Gamechanger from INSERTED;
IF @Old_Gamechanger != @New_Gamechanger
BEGIN
INSERT INTO [dbo].T_History(ChangeDate, Reason, Callcenter_ID, Old_Gamechanger, New_Gamechanger)
SELECT GETDATE(), 'Time for a change', Callcenter_ID, @Old_Gamechanger, @New_Gamechanger
FROM deleted
;
END
END
请记住,当您使用一个“代替”触发器时,它不会在触发器中自动提交插入操作,除非您明确告诉它这样做。 “代替”意味着执行此操作而不是通常的操作,因此不会发生任何正常的插入操作。