SQL Server 2012触发器:为每行

时间:2017-10-06 13:10:27

标签: sql sql-server-2012 triggers dynamic-sql

我在表中有一个触发器,它保留所有更改(插入,更新,删除)。当我每次只插入一行时它工作正常。但是,当我尝试一次插入多行时,我收到此错误:

  

子查询返回的值超过1。这是不允许的   子查询跟随=,!=,<,< =,>,> =或当子查询用作   表达。

这是触发器的代码(我删除了一些不需要缩短代码的部分,如变量声明等。)

更新: 当#tempTrigT包含多行时,实际错误就在这些行中:

Select * into #tempTrigT from (select * from deleted where @Action in ( 'U','D')) A UNION (select * from inserted where @Action ='I')

    set @sql = 'set @audit_oldvalue=(select cast([' +@Item +'] as NVARCHAR(4000)) from #tempTrigT)';
    EXEC SP_EXECUTESQL @sql,N'@audit_oldvalue sql_variant OUTPUT',@audit_oldvalue OUTPUT -- If inserted @audit_oldvalue gets the new value

    set @sql = 'set @audit_value=(select cast(i.[' +@Item +'] as NVARCHAR(4000)) from dbo.TForms i  inner join #tempTrigT d on i.id = d.id)';
    EXEC SP_EXECUTESQL @sql,N'@audit_value sql_variant OUTPUT',@audit_value OUTPUT

如何将其更改为多行?

1 个答案:

答案 0 :(得分:2)

您缺少行标识符,因此每个循环只处理一行。类似的东西:

  • DECLARE @ID int = (SELECT MIN(id) FROM #tempTrigT)在循环开始时定义一行
  • WHERE id = @ID在整个循环中过滤到此行
  • 循环结束时
  • DELETE FROM #tempTrigT WHERE id = @ID,当id完成处理

然后,如果id可以在#tempTrigT中重复,则可能无效。

尽管如此......

我肯定会考虑将其分成多个触发器,并通过尝试循环删除或插入的记录并相应地处理它们来节省您所面临的复杂性。我还会考虑简化审核流程。最终目标是能够回顾过去的记录,您可以非常简单地实现这些记录:

INSERT INTO [dbo].[AuditTrailTForms] (TForms_Cols, ChangeDate, Change_User, Change_Type)
    SELECT T.*, GETDATE(), COALESCE(ModifiedBy,suser_name()), 'Inserted'
    FROM inserted i
    JOIN TForms T on i.id = T.id

然后,您可以担心在查询这些表时更容易查看稍后更改的列值:

SELECT *
FROM (SELECT *, GETDATE(), 'Current', 'Current'
      FROM TForms
      WHERE ID = @AuditID
         UNION ALL
      SELECT *
      FROM AuditTrailTForms
      WHERE ID = @AuditID
      --AND Change_Type = 
      --AND Change_User = 
     ) T
ORDER BY ChangeDate DESC

编辑:使用标识列

您可以使用标识列为每个循环定义一行,如下所示:

DECLARE @TotalRows int = (SELECT MAX(identityColumn) FROM #tempTrigT
DECLARE @RowID int = 1
WHILE @RowID <= @TotalRows
    BEGIN
        --Do stuff
        --For Example
            SET @sql = 'set @audit_oldvalue=(SELECT cast([' +@Item +'] as NVARCHAR(4000)) 
                                             FROM #tempTrigT 
                                             WHERE T.IdentityColumn = @RowID)';
            EXEC SP_EXECUTESQL @sql,N'@audit_oldvalue sql_variant OUTPUT',@audit_oldvalue OUTPUT

        --then increment to the next row when you're done
        SET @RowID = @RowID + 1
    END