如何获取更新的字段名称&他们从触发器的价值

时间:2014-09-06 20:25:18

标签: sql-server triggers dynamic-sql

我可以弄清楚如何从触发器获取更新的字段名称。假设我有客户表,如果客户名称和位置名称已更新,那么我们可以从触发器获取这些字段名称发出以下声明

DECLARE @idTable INT
SELECT @idTable = T.id FROM sysobjects P JOIN sysobjects T ON P.parent_obj = T.id WHERE P.id = @@procid
DECLARE @Columns_Updated VARCHAR(50)

SELECT  @Columns_Updated = ISNULL(@Columns_Updated + ', ', '') + name 
FROM    syscolumns 
WHERE   id = @idTable   
AND     CONVERT(VARBINARY,REVERSE(COLUMNS_UPDATED())) & POWER(CONVERT(BIGINT, 2), colorder - 1)  > 0

但我也希望新值对于那些字段名称,因为我想在字符串变量中生成更新语句,如

SET @SQL="update customer set cutsname='ALFKI',locname='kolkata' where id=10"

我可以获得cutname&来自上面的sql的locname,但我不知道如何获取这些字段的值。

主要关注的是如何知道值以及如何在字符串变量中构造更新语句,名称为&值。

如果有人分享这个想法,那将是很有帮助的。感谢

更新

非常容易我们可以像这样从触发器生成select语句

SET @SQL='SELECT '+@Columns_Updated+' FROM MYTable'

我想必须有一些技巧来生成更新语句,其中更新的列名称来自trigger.if你有任何想法然后plzz与我分享。感谢

1 个答案:

答案 0 :(得分:0)

我认为在您的情况下,您需要使用SET CONTEXT_INFO命令。

您可以使用SET CONTEXT_INFO命令将最多128个字节的数据与当前连接相关联。

现在您可以做的是生成一个 UNIQUEIDENTIFIER 并在上下文中设置它。

DECLARE @newId UNIQUEIDENTIFIER, @Ctx VARBINARY(128)
SET @newId = newid()

SELECT @Ctx = CONVERT(VARBINARY(128), @newId)
SET CONTEXT_INFO @Ctx

现在在您的触发器中检索此上下文的值,如此 -

DECLARE @CtxData varchar(128)
SELECT @CtxData = CONVERT(VarChar(128), CONTEXT_INFO())

并将更新后的列及其新值跟踪到触发器中的一个新表(或临时表)中,如下所示 -

IF UPDATE(cutsname)
BEGIN
    SET @colName = 'cutsname'

    SELECT @colVal = cutsname
    FROM inserted
END

INSERT INTO newTable (
    ColName
    ,ColValue
    ,NewUniqueId
    )
VALUES (
    @colName
    ,@colVal
    ,@CtxData
    )

和其他专栏相同。

现在在触发器之外访问此表格,如下所示,在您的SP中跟踪,并在审核表中跟踪。

SELECT *
FROM newTable
WHERE NewUniqueId = @newId -- this @newId is the id which we set in CONTEXT_INFO

就是这样。那么你可以根据你的要求重新定义这个逻辑,如果你发现它太长了。

EDITED

好的,我已经通过组合INSERTEDDELETED虚拟表重新定义了插入查询。

INSERT INTO newTable (
    ColName
    ,ColValue
    ,NewUniqueId
    )
SELECT CASE -- to track column name
        WHEN I.cutsname <> D.cutsname
            THEN 'cutsname'
        ELSE ''
        END
    ,CASE -- to track updated new value
        WHEN I.cutsname <> D.cutsname
            THEN I.cutsname
        ELSE ''
        END
    ,@CtxData

UNION ALL

    CASE 
        WHEN I.locname <> D.locname
            THEN 'locname'
        ELSE ''
        END
    ,CASE 
        WHEN I.locname <> D.locname
            THEN I.locname
        ELSE ''
        END
    ,@CtxData

UNION ALL

    CASE 
        WHEN I.OtherColumn <> D.OtherColumn
            THEN 'OtherColumn'
        ELSE ''
        END
    ,CASE 
        WHEN I.OtherColumn <> D.OtherColumn
            THEN I.OtherColumn
        ELSE ''
        END
    ,@CtxData
FROM INSERTED I
JOIN DELETED D ON I.id = D.id

所以现在没有必要为每一列使用IF UPDATE(colName) ...感谢Aaron Bertrand在评论中指出了更新()。

=============================================== ================================= 除了上述解决方案,您还可以在sql server 2008中使用Change Data Capture功能。

this link.有一篇精彩的文章,至少可以通过它。