我已经和这个人摔跤了好几天了。我有一个表触发器,它为每个Insert,Update或Delete操作创建一个审计记录,并将其放在相邻数据库的相应审计表中。此新审核记录包含源表主键值,操作类型,记录的XML快照,当前日期和当前用户。
上面列出的每条信息都是从INSERTED \ DELETED表中分配\计算并分配给参数值,然后将这些参数值传递给执行一段动态SQL以插入新记录的存储过程。为了这个问题,动态SQL是一个简单的INSERT语句(如下所示):
INSERT INTO [340bAudit].[aud].[TableName]
(
RecordID
,ActionType
,xml_snapshot
,ModifiedDate
,ModifiedBy
)
VALUES (@RecordPK
,@action
,@data
,GETDATE()
,SYSTEM_USER
)
只要只有一条记录被更新,这个触发器似乎工作正常,但是一旦出现多个记录在一个语句中更新的情况,我就明白了:
子查询返回的值超过1。子查询时不允许这样做 follow =,!=,<,< =,>,> =或者当子查询用作 表达。声明已经终止。
触发器如下所示:
ALTER TRIGGER [dbo].[RollOver_onUpdate] ON [dbo].[RollOver]
AFTER INSERT, update, DELETE
FOR EACH ROW
AS
BEGIN
/******** Audit *******/
DECLARE @TableName varchar(50)
,@RecordPK varchar(10)
,@action char(1)
,@data xml
SET @TableName = 'RollOver'
SET @RecordPK = (SELECT DISTINCT RollOverID FROM INSERTED)
SET @action = 'I'; -- Set Action to Insert by default.
IF EXISTS (SELECT * FROM DELETED)
BEGIN
SET @action =
CASE
WHEN EXISTS (SELECT * FROM INSERTED)
THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END
END
SET @data = CASE WHEN @action <> 'D' THEN (SELECT'<rows>' + (SELECT * FROM INSERTED i FOR xml PATH) + '</rows>')
ELSE (SELECT'<rows>' + (SELECT * FROM DELETED d FOR xml PATH) + '</rows>')
END
--Execute Audit Record Creation
EXECUTE sp_CreateAuditRecord @Table = @TableName
,@RecordID = @RecordPK
,@ActionType = @action
,@XML = @data
END
在这种情况下,我可以改变此触发器以按行执行吗?如果没有,我从哪里开始?
我非常希望保留我对dyanamic SQL的灵活性,因为我数据库中的每个表都使用相同的审计逻辑,这是第一个也是唯一一个似乎有问题的表,我认为这是由于这个表的'使用'。
答案 0 :(得分:0)
这就是我想出的。它绝对不是最优雅的代码,但它可以解决我的问题。感谢您的回复。我会投一票,但没有人给我答复接受。
/******** Audit *******/
DECLARE @action char(1)
SET @action = 'I'; -- Set Action to Insert by default.
IF @@ROWCOUNT = 0
RETURN
IF EXISTS (SELECT * FROM DELETED)
BEGIN
SET @action = CASE WHEN EXISTS (SELECT * FROM INSERTED)
THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END
INSERT INTO [340bAudit].[aud].[Orders]
(
RecordID
,ActionType
,xml_snapshot
,ModifiedDate
,ModifiedBy
)
SELECT d.OrderID,
CASE WHEN EXISTS (SELECT * FROM INSERTED)
THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END ,
CASE WHEN @action <> 'D' THEN (SELECT'<rows>' + (SELECT * FROM INSERTED i FOR xml PATH) + '</rows>')
ELSE (SELECT'<rows>' + (SELECT * FROM DELETED d FOR xml PATH) + '</rows>') END,
GETDATE(),
SYSTEM_USER
FROM DELETED d
END
-- INSERTED Order Records
INSERT INTO [340bAudit].[aud].[Orders]
(
RecordID
,ActionType
,xml_snapshot
,ModifiedDate
,ModifiedBy
)
SELECT i.OrderID,
@action,
(SELECT'<rows>' + (SELECT * FROM INSERTED i FOR xml PATH) + '</rows>'),
GETDATE(),
SYSTEM_USER
FROM INSERTED i