SQL 服务器触发器从存储过程动态更新日志列
SQL Server trigger to Log columns updated from a stored procedure dynamically
我有一个存储过程,它在执行时会在单个 table 中更新约 100 列。
我想在受影响的 table 上创建一个触发器,它将:
确定所有(实际)更新的值
(所以如果新值为'1',旧值为'1',则忽略)
从实际变化值列表中,得到列名和数据值
获取列名和旧数据值并通过插入将它们存储到日志中table
(INSERT ColumnName, Value INTO LogTable)
我有一个可行的解决方案,但我必须创建一个临时文件 table 并在临时文件 table 中为我知道受影响的每一列插入一行......就像拥有其中的 100 个:
INSERT INTO @TempTable (
ID,
ColumnName,
OldColumnValue
)
SELECT i.ID, 'Column1', i.Column1
FROM inserted i
INNER JOIN deleted d ON d.ID = i.ID
WHERE COALESCE(d.Column1, '') != COALESCE(i.Column1, '')
在为 column1 一直插入到 column100 之后,我只需将 @TempTable 中的所有记录插入到日志中 table。
必须有更动态的方法来解决这个问题,但我想不出。
*为了简单起见,假设值将始终为 [TEXT],LogTable 中的值也将如此。
没有您的 table 定义,我无法完整回答这个问题,但是,您在这里需要做的是对所有数据进行逆透视,然后当值不等于另一个时,将其插入您的日志 table。这意味着您的查询需要如下所示:
INSERT INTO dbo.LogTable (ID,
ColumnName,
OldColumnValue)
SELECT d.ID,
V.ColumnName,
V.OldColumnValue
FROM deleted d
JOIN inserted i ON d.ID = i.ID
CROSS APPLY (VALUES(N'Column1',i.Column1, d.Column1),
(N'Column2',i.Column2, d.Column2),
(N'Column3',i.Column3, d.Column3),
(N'Column4',i.Column4, d.Column4))V(ColumnName, NewColumnValue, OldColumnValue)
WHERE V.NewColumnValue != V.OldColumnValue
OR (V.NewColumnValue IS NULL AND V.OldColumnValue IS NOT NULL)
OR (V.NewColumnValue IS NOT NULL AND V.OldColumnValue IS NULL);
但是请注意,列必须由相同的数据类型组成,我怀疑您的所有列都是相同的数据类型。因此,您将需要明确地将所有列 CONVERT
设为 (n)varchar
。对于日期和时间值的列,我强烈建议您也使用显式 CONVERT
中的样式代码;像 112
代表 date
,也许 126
代表其他日期和时间数据类型。
我有一个存储过程,它在执行时会在单个 table 中更新约 100 列。
我想在受影响的 table 上创建一个触发器,它将:
确定所有(实际)更新的值 (所以如果新值为'1',旧值为'1',则忽略)
从实际变化值列表中,得到列名和数据值
获取列名和旧数据值并通过插入将它们存储到日志中table (INSERT ColumnName, Value INTO LogTable)
我有一个可行的解决方案,但我必须创建一个临时文件 table 并在临时文件 table 中为我知道受影响的每一列插入一行......就像拥有其中的 100 个:
INSERT INTO @TempTable (
ID,
ColumnName,
OldColumnValue
)
SELECT i.ID, 'Column1', i.Column1
FROM inserted i
INNER JOIN deleted d ON d.ID = i.ID
WHERE COALESCE(d.Column1, '') != COALESCE(i.Column1, '')
在为 column1 一直插入到 column100 之后,我只需将 @TempTable 中的所有记录插入到日志中 table。
必须有更动态的方法来解决这个问题,但我想不出。
*为了简单起见,假设值将始终为 [TEXT],LogTable 中的值也将如此。
没有您的 table 定义,我无法完整回答这个问题,但是,您在这里需要做的是对所有数据进行逆透视,然后当值不等于另一个时,将其插入您的日志 table。这意味着您的查询需要如下所示:
INSERT INTO dbo.LogTable (ID,
ColumnName,
OldColumnValue)
SELECT d.ID,
V.ColumnName,
V.OldColumnValue
FROM deleted d
JOIN inserted i ON d.ID = i.ID
CROSS APPLY (VALUES(N'Column1',i.Column1, d.Column1),
(N'Column2',i.Column2, d.Column2),
(N'Column3',i.Column3, d.Column3),
(N'Column4',i.Column4, d.Column4))V(ColumnName, NewColumnValue, OldColumnValue)
WHERE V.NewColumnValue != V.OldColumnValue
OR (V.NewColumnValue IS NULL AND V.OldColumnValue IS NOT NULL)
OR (V.NewColumnValue IS NOT NULL AND V.OldColumnValue IS NULL);
但是请注意,列必须由相同的数据类型组成,我怀疑您的所有列都是相同的数据类型。因此,您将需要明确地将所有列 CONVERT
设为 (n)varchar
。对于日期和时间值的列,我强烈建议您也使用显式 CONVERT
中的样式代码;像 112
代表 date
,也许 126
代表其他日期和时间数据类型。