一旦你解决您的触发涵盖所有三个操作,
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
IF EXISTS (SELECT 1 FROM deleted)
BEGIN
SET @action = 'UPDATE';
END
ELSE
BEGIN
SET @action = 'INSERT';
END
ELSE
BEGIN
SET @action = 'DELETE';
END
另一个替代方案是三个独立的触发器,每一个动作。
如果您正在使用它,请谨慎使用MERGE ...或者在您迁移到SQL Server 2008或更高版本时做好准备。
编辑
我想你可能是后是INSTEAD OF
触发,而不是(多么讽刺)。这是一个例子。让我们考虑一个非常简单的表与PK柱和独特的列:
CREATE TABLE dbo.foobar(id INT PRIMARY KEY, x CHAR(1) UNIQUE);
GO
和一个简单的日志表赶上活动:
CREATE TABLE dbo.myLog
(
foobar_id INT,
oldValue XML,
newValue XML,
[action] CHAR(6),
success BIT
);
GO
以下INSTEAD OF
触发器将拦截INSERT/UPDATE/DELETE
命令,试图复制他们会做的工作,并记录它是否失败或成功:
CREATE TRIGGER dbo.foobar_inst
ON dbo.foobar
INSTEAD OF INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @action CHAR(6), @success BIT;
SELECT @action = 'DELETE', @success = 1;
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
IF EXISTS (SELECT 1 FROM deleted)
SET @action = 'UPDATE';
ELSE
SET @action = 'INSERT';
END
BEGIN TRY
IF @action = 'INSERT'
INSERT dbo.foobar(id, x) SELECT id, x FROM inserted;
IF @action = 'UPDATE'
UPDATE f SET x = i.x FROM dbo.foobar AS f
INNER JOIN inserted AS i ON f.id = i.id;
IF @action = 'DELETE'
DELETE f FROM dbo.foobar AS f
INNER JOIN inserted AS i ON f.id = i.id;
END TRY
BEGIN CATCH
ROLLBACK; -- key part here!
SET @success = 0;
END CATCH
IF @action = 'INSERT'
INSERT dbo.myLog SELECT i.id, NULL,
(SELECT * FROM inserted WHERE id = i.id FOR XML PATH),
@action, @success FROM inserted AS i;
IF @action = 'UPDATE'
INSERT dbo.myLog SELECT i.id,
(SELECT * FROM deleted WHERE id = i.id FOR XML PATH),
(SELECT * FROM inserted WHERE id = i.id FOR XML PATH),
@action, @success FROM inserted AS i;
IF @action = 'DELETE'
INSERT dbo.myLog SELECT d.id,
(SELECT * FROM deleted WHERE id = d.id FOR XML PATH),
NULL, @action, @success FROM deleted AS d;
END
GO
让我们试试一些非常简单的隐式交易上陈述:
-- these succeed:
INSERT dbo.foobar SELECT 1, 'x';
GO
INSERT dbo.foobar SELECT 2, 'y';
GO
-- fails with PK violation:
INSERT dbo.foobar SELECT 1, 'z';
GO
-- fails with UQ violation:
UPDATE dbo.foobar SET x = 'y' WHERE id = 1;
GO
检查日志:
SELECT foobar_id, oldValue, newValue, action, success FROM dbo.myLog;
结果:
foobar_id oldValue newValue action success
--------- ----------------------------- ----------------------------- ------ -------
1 NULL <row><id>1</id><x>x</x></row> INSERT 1
2 NULL <row><id>2</id><x>y</x></row> INSERT 1
1 NULL <row><id>1</id><x>z</x></row> INSERT 0
1 <row><id>1</id><x>x</x></row> <row><id>1</id><x>y</x></row> UPDATE 0
当然,你可能希望在日志表等栏目,如用户,日期/时间,甚至可能是原来的说法。这并不意味着要成为全面的审计解决方案,只是一个例子。
正如Mikael指出的那样,这依赖于外部批处理是启动隐式事务的单个命令。如果外部批处理是明确的多语句事务,则必须测试该行为。
另请注意,在UPDATE影响零行的情况下,这不会捕获“失败”。因此,您需要明确定义“失败”的含义 - 在某些情况下,您可能需要在外部代码中构建自己的失败处理,而不是触发器。
您的触发器是FOR UPDATE触发器。你将如何捕获INSERT和DELETE操作? –
#Aaron Bertrand。那我该如何实现呢? – Anuya
我的观点是你的触发器说'FOR UPDATE' ...需要'更新,插入,删除',如果你想捕获所有三个动作。 –