Tsql 在多行插入上错误触发SQL触发器

Tsql 在多行插入上错误触发SQL触发器,tsql,triggers,dynamic-sql,sql-insert,Tsql,Triggers,Dynamic Sql,Sql Insert,我已经和这个摔跤好几天了。我有一个表触发器,它为每个插入、更新或删除操作创建一个审计记录,并将其放在相邻数据库中相应的审计表中。此新审核记录包含源表主键值、操作类型、记录的XML快照、当前日期和当前用户 上面列出的每一条信息都是从插入的/删除的表中分配/计算出来的,并分配给参数值,然后将参数值传递给一个存储过程,该存储过程执行一条动态SQL以插入新记录。对于这个问题,动态SQL是一个简单的INSERT语句,如下所示: INSERT INTO [340bAudit].[aud].[

我已经和这个摔跤好几天了。我有一个表触发器,它为每个插入、更新或删除操作创建一个审计记录,并将其放在相邻数据库中相应的审计表中。此新审核记录包含源表主键值、操作类型、记录的XML快照、当前日期和当前用户

上面列出的每一条信息都是从插入的/删除的表中分配/计算出来的,并分配给参数值,然后将参数值传递给一个存储过程,该存储过程执行一条动态SQL以插入新记录。对于这个问题,动态SQL是一个简单的INSERT语句,如下所示:

        INSERT INTO [340bAudit].[aud].[TableName]
            (
                RecordID
                ,ActionType
                ,xml_snapshot
                ,ModifiedDate
                ,ModifiedBy
            )
            VALUES (@RecordPK 
                ,@action
                ,@data 
                ,GETDATE() 
                ,SYSTEM_USER 
                   )
只要只更新一条记录,此触发器就可以正常工作,但一旦出现在一条语句中更新多条记录的情况,我会得到以下结果:

子查询返回了多个值。当子查询 如下=,!=,=或者当子查询用作 表示声明已终止

触发器如下所示:

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
在这种情况下,我可以将此触发器更改为按行执行吗?如果没有,我该怎么办


我非常希望保留动态SQL的灵活性,因为我数据库中的每个表都使用相同的审计逻辑,这是第一个也是唯一一个出现问题的表,我相信这是由于“使用”了这个表

这就是我想到的。这肯定不是最优雅的代码,但它可以工作并解决我的问题。谢谢你的回复。我会投赞成票,但没有人给我一个答案让我接受

/******** 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 

看一看最佳实践:为多行操作编写SQL Server触发器使其基于集合并摆脱过程调用谢谢,我来看看。看起来该链接不再有效。任何人都有类似资源的替代链接。