【发布时间】:2021-03-08 14:10:44
【问题描述】:
我在表DEP_MARCHE 上创建了一个AFTER UPDATE 触发器,它将在我的审计表AuditDepMarche 中插入两行:一行用于旧值(来自虚拟表DELETED),第二行包含新值DEP_MARCHE 的所有列的值(来自虚拟表INSERTED)(DEP_MARCHE 和AuditDepMarche 具有相同的结构)。我还创建了一个AFTER INSERT 触发器,它在我的审计表中添加了一行。
问题是当我在DEP_MARCHE 中插入一些东西时,AFTER UPDATE 触发器被触发,因此三行被添加到我的审计表中(一行由AFTER INSERT 触发器添加,另外两行由@987654333 @触发器)
我在互联网上搜索,我找到的解决方案是:为两个 (AFTER INSERT, UPDATE) 创建一个触发器并在虚拟表 DELETED 上测试,如果它是空的,那么我在插入触发器之后运行查询,否则我运行更新后触发器的查询,类似这样(但它对我不起作用):
CREATE TRIGGER foo_AlteredRecord
ON [dbo].[Foo]
AFTER INSERT, UPDATE
AS
BEGIN
DECLARE @DelCount int;
DECLARE @InsCount int;
SELECT @InsCount = COUNT(Col1) FROM INSERTED;
SELECT @DelCount = COUNT(Col1) FROM DELETED;
IF @InsCount > 0 AND @DelCount = 0
BEGIN
-- At least 1 row inserted. Your Insert Trigger logic here
END
ELSE IF @DelCount > 0 AND @InsCount > 0
BEGIN
-- old row deleted, new row inserted; both indicates an update.
-- your update logic here.
END
END
在我的代码中实现了这个逻辑之后,每当我在DEP_MARCHE 表中插入一些东西时,它开始在我的审计表中添加不是 3 行而是 5 行(一行用于插入触发器,两行;旧& 新值,重复 => 4 行)
这是我的代码,我将不胜感激
Drop trigger if exists DepMarcheAudit_UPDATE_INSERT
go
CREATE TRIGGER DepMarcheAudit_UPDATE_INSERT
ON DEP_MARCHE
AFTER UPDATE, INSERT
AS
BEGIN
Declare @DelCount int;
Declare @InsCount int;
SELECT @InsCount = Count(*) FROM INSERTED;
SELECT @DelCount = Count(*) FROM DELETED;
-----------AFTER UPDATE TRIGGER TRANSACTIONS---------
IF @InsCount > 0 AND @DelCount > 0
BEGIN
DECLARE @AUDIT_OPERATION_OLD VARCHAR(50)
SET @AUDIT_OPERATION_OLD = 'mise à jour (Old values)'
DECLARE @AUDIT_OPERATION_NEW VARCHAR(50)
SET @AUDIT_OPERATION_NEW = 'mise à jour (New values)'
declare @StartTime datetimeoffset(7) = sysdatetimeoffset();
INSERT INTO [dbo].[DepMarcheAudit](
[CODE_MARCHE]
,[AUDIT_OPERATION_TYPE]
,[AUDIT_OPERATION_DATE]
,[AUDIT_OPERATION_TIME]
,[AUDIT_ID_USER]
,[LIBELLE_MARCHE]
,[CODE_FOURNISSEUR]
,[NUMERO_MARCHE]
,[OBSERVATION_MARCHE]
,[CODE_NATURE]
,[CODE_AO]
,[DOC_CONTRAT]
,[IS_DEPENSE_SIMPLIFIEE],
[startTime]
)
SELECT
[CODE_MARCHE]
,@AUDIT_OPERATION_OLD
,GETDATE()
,(CONVERT([time],getdate(),0))
,HOST_NAME()
,[LIBELLE_MARCHE]
,[CODE_FOURNISSEUR]
,[NUMERO_MARCHE]
,[OBSERVATION_MARCHE]
,[CODE_NATURE]
,[CODE_AO]
,[DOC_CONTRAT]
,[IS_DEPENSE_SIMPLIFIEE]
,@StartTime
FROM DELETED;
INSERT INTO [dbo].[DepMarcheAudit](
[CODE_MARCHE]
,[AUDIT_OPERATION_TYPE]
,[AUDIT_OPERATION_DATE]
,[AUDIT_OPERATION_TIME]
,[AUDIT_ID_USER]
,[LIBELLE_MARCHE]
,[CODE_FOURNISSEUR]
,[NUMERO_MARCHE]
,[OBSERVATION_MARCHE]
,[CODE_NATURE]
,[CODE_AO]
,[DOC_CONTRAT]
,[IS_DEPENSE_SIMPLIFIEE]
,[startTime]
)
SELECT
[CODE_MARCHE]
,@AUDIT_OPERATION_NEW
,getdate()
,(CONVERT([time],getdate(),0))
,HOST_NAME()
,[LIBELLE_MARCHE]
,[CODE_FOURNISSEUR]
,[NUMERO_MARCHE]
,[OBSERVATION_MARCHE]
,[CODE_NATURE]
,[CODE_AO]
,[DOC_CONTRAT]
,[IS_DEPENSE_SIMPLIFIEE]
,@StartTime
FROM INSERTED;
END
--------------------AFTER INSERT TRIGGER TRANSACTION-----------------------------
ELSE IF @InsCount > 0 AND @DelCount = 0
BEGIN
DECLARE @AUDIT_OPERATION VARCHAR(50)
SET @AUDIT_OPERATION = 'Insertion'
INSERT INTO [dbo].[DepMarcheAudit](
[CODE_MARCHE]
,[AUDIT_OPERATION_TYPE]
,[AUDIT_OPERATION_DATE]
,[AUDIT_OPERATION_TIME]
,[AUDIT_ID_USER]
,[LIBELLE_MARCHE]
,[CODE_FOURNISSEUR]
,[NUMERO_MARCHE]
,[OBSERVATION_MARCHE]
,[CODE_NATURE]
,[CODE_AO]
,[DOC_CONTRAT]
,[IS_DEPENSE_SIMPLIFIEE]
,[startTime])
SELECT
[CODE_MARCHE]
,@AUDIT_OPERATION
,GETDATE()
,(CONVERT([time],getdate(),0))
,HOST_NAME()
,[LIBELLE_MARCHE]
,[CODE_FOURNISSEUR]
,[NUMERO_MARCHE]
,[OBSERVATION_MARCHE]
,[CODE_NATURE]
,[CODE_AO]
,[DOC_CONTRAT]
,[IS_DEPENSE_SIMPLIFIEE]
, sysdatetimeoffset()
FROM INSERTED;
END
END
GO
【问题讨论】:
-
如果
INSERT和UPDATE需要不同的逻辑,最好创建单独的触发器。 -
照拉努的建议去做。将两个触发器分开,一个用于 AFTER INSERT,另一个用于 AFTER UPDATE。这将为您简化事情,并让任何人事后进行调整都可以管理。
-
别忘了添加一个 SET NOCOUNT ON。
-
你有插入触发器和插入和更新触发器吗?我看不出你们还有什么被解雇的。
-
@Larnu 一开始我创建了单独的触发器,然后我也遇到了问题:更新触发器总是在插入后触发
标签: sql-server triggers