【问题标题】:How to set two dynamic temporary global variables for triggers in SQL server?如何在 SQL Server 中为触发器设置两个动态临时全局变量?
【发布时间】:2014-07-25 14:30:01
【问题描述】:

我有一个存储过程来更新数据,它是通过 C# 调用的。我还为我的表设置了几个触发器,它们在数据更改时将审计信息插入到审计表中。

问题是我在审计表中有两列叫做changedBy(UserName)和changeSetID,我只能从C#中检索它们,我可以将它们作为参数传递给存储过程,然后我不知道如何让trigger 获取这两个变量的值。

本来我用context_info作为全局变量,但是需要传入两个变量才能触发。

【问题讨论】:

  • 我看到的获得倍数的唯一方法......是在原始表上拥有“LastChangedBy”和“LastChangeSetId”列......所以你可以得到那个信息.....在@inserted 上的触发器中。

标签: sql sql-server stored-procedures triggers global-variables


【解决方案1】:

几种方法:

1) 正如 granadaCoder 建议的那样,将这些列添加到更新后的表中,以便触发器能够访问它们

2) 在 proc 开始时禁用触发器,在 proc 中包含对审计表的插入(而不是让触发器执行它们),然后在最后重新启用触发器。

3) 将此信息保存在永久表中。有一个表,其中包含更新表的 UniqueID,以及“changedBy”和“changeSetID”列。在 proc 的开头,使用从 C# 传递的参数更新此表。在触发器中,将join插入到这个表中,得到你需要的两列的值。

【讨论】:

    【解决方案2】:

    我实际上想出了一个解决方法。

    首先,我将我的用户名和 changesetID 作为参数从 C# 传递到 SQL 存储过程。在我的存储过程中,我将 CONTEXT_INFO 设置为 userName 和 changeSetID 的组合

    Declare @userAndSetID VARBINARY(128)
    SET @UserName = @UserName + ',' + @ChangeSetID + ','
    SET @userAndSetID = CAST(CAST(@UserName AS NVARCHAR(MAX)) AS VARBINARY(128));
    SET CONTEXT_INFO @userAndSetID
    

    在我的触发器中,我使用拆分字符串函数从 CONTEXT_INFO() 中检索我的两个变量:

     select @ChangedBy = value from dbo.fn_Split((CAST (CONTEXT_INFO() AS NVARCHAR(MAX))),',') where position = 1;
     select @changesetID = value from dbo.fn_Split((CAST (CONTEXT_INFO() AS NVARCHAR(MAX))),',') where position = 2;
    

    这里是分割字符串函数,它得到一个用任何符号分隔的字符串,并将它们逐行放入表变量中:

        CREATE FUNCTION [dbo].[fn_Split](@text nvarchar(MAX), @delimiter nvarchar(20) = ' ')
        RETURNS @Strings TABLE
        (    
          position int IDENTITY PRIMARY KEY,
          value nvarchar(1500)   
        )
        AS
        BEGIN
    
        DECLARE @index int
        SET @index = -1 
    
        WHILE (LEN(@text) > 0) 
    
          BEGIN 
            SET @index = CHARINDEX(@delimiter , @text)  
            IF (@index = 0) AND (LEN(@text) > 0)  
              BEGIN  
                INSERT INTO @Strings VALUES (@text)
                  BREAK  
              END 
    
            IF (@index > 1)  
              BEGIN  
                INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))   
                SET @text = RIGHT(@text, (LEN(@text) - @index))  
              END 
            ELSE
              SET @text = RIGHT(@text, (LEN(@text) - @index)) 
            END
          RETURN
    
        END
    

    这只是一种解决方法,正如@Tab Alleman 建议的那样,解决此问题的最佳方法是将变量保存在数据库中的某个位置,但由于我目前不想修改数据库,因此此解决方案可以诀窍。

    【讨论】:

      【解决方案3】:

      如果正在使用 SQL 2016,现在有更好的方法来做到这一点,通过 SESSION_CONTEXT

      插入 EXEC sys.sp_set_session_context @key = N'ID', @value = 'Some Text', @read_only = 1;

      读出 PRINT SESSION_CONTEXT(N'ID');

      对于第二个选项,您可以指定不同的键

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-24
        相关资源
        最近更新 更多