SQL Server 更新触发器,仅获取修改的字段
我知道COLUMNS_UPDATED
,我需要一些快速的快捷方式(如果有人做过,我已经在做了,但如果有人可以节省我的时间,我会感激它)
我基本上需要一个 XML仅更新列值,我需要它用于复制目的。
SELECT * FROM Insert 为我提供了每一列,但我只需要更新的列。
像下面这样的东西
CREATE TRIGGER DBCustomers_Insert
ON DBCustomers
AFTER UPDATE
AS
BEGIN
DECLARE @sql as NVARCHAR(1024);
SET @sql = 'SELECT ';
I NEED HELP FOR FOLLOWING LINE ...., I can manually write every column, but I need
an automated routin which can work regardless of column specification
for each column, if its modified append $sql = ',' + columnname...
SET @sql = $sql + ' FROM inserted FOR XML RAW';
DECLARE @x as XML;
SET @x = CAST(EXEC(@sql) AS XML);
.. use @x
END
I am aware of COLUMNS_UPDATED
, well I need some quick shortcut (if anyone has made, I am already making one, but if anyone can save my time, I will appriciate it)
I need basicaly an XML of only updated column values, I need this for replication purpose.
SELECT * FROM inserted gives me each column, but I need only updated ones.
something like following...
CREATE TRIGGER DBCustomers_Insert
ON DBCustomers
AFTER UPDATE
AS
BEGIN
DECLARE @sql as NVARCHAR(1024);
SET @sql = 'SELECT ';
I NEED HELP FOR FOLLOWING LINE ...., I can manually write every column, but I need
an automated routin which can work regardless of column specification
for each column, if its modified append $sql = ',' + columnname...
SET @sql = $sql + ' FROM inserted FOR XML RAW';
DECLARE @x as XML;
SET @x = CAST(EXEC(@sql) AS XML);
.. use @x
END
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
这是使用唯一记录和 UpdatedBy 用户跟踪更新的列值日志的完美示例。
This is perfect example for track log of updated columnwise value with unique records and UpdatedBy user.
我有另一个完全不同的解决方案,它根本不使用 COLUMNS_UPDATED,也不依赖于在运行时构建动态 SQL。 (您可能想在设计时使用动态 SQL,但那是另一个故事了。)
基本上,您从 插入和删除的表,对每个表进行逆透视,这样您就只剩下每个表的唯一键、字段值和字段名称列。 然后将两者结合起来并过滤任何更改的内容。
这是一个完整的工作示例,包括一些测试调用以显示记录的内容。
因此,不要搞乱 bigint 位域和 arth 溢出问题。 如果您知道在设计时要比较的列,那么您不需要任何动态 SQL。
缺点是输出采用不同的格式,并且所有字段值都转换为 sql_variant,第一个可以通过再次旋转输出来修复,第二个可以通过根据您对数据的了解重新转换回所需的类型来修复表的设计,但是这两者都需要一些复杂的动态sql。 这两者在 XML 输出中可能都不是问题。 这个问题的作用类似于以相同的格式获取输出。
编辑:查看下面的评论,如果您有一个可以更改的自然主键,那么您仍然可以使用此方法。 您只需使用 NEWID() 函数添加默认填充有 GUID 的列。 然后,您可以使用该列代替主键。
您可能希望为此字段添加索引,但由于触发器中删除和插入的表位于内存中,因此可能不会被使用,并且可能会对性能产生负面影响。
I've another completely different solution that doesn't use COLUMNS_UPDATED at all, nor does it rely on building dynamic SQL at runtime. (You might want to use dynamic SQL at design time but thats another story.)
Basically you start with the inserted and deleted tables, unpivot each of them so you are just left with the unique key, field value and field name columns for each. Then you join the two and filter for anything that's changed.
Here is a full working example, including some test calls to show what is logged.
So no messing around with bigint bitfields and arth overflow problems. If you know the columns you want to compare at design time then you don't need any dynamic SQL.
On the downside the output is in a different format and all the field values are converted to sql_variant, the first could be fixed by pivoting the output again, and the second could be fixed by recasting back to the required types based on your knowledge of the design of the table, but both of these would require some complex dynamic sql. Both of these might not be an issue in your XML output. This question does something similar to getting the output back in the same format.
Edit: Reviewing the comments below, if you have a natural primary key that could change then you can still use this method. You just need to add a column that is populated by default with a GUID using the NEWID() function. You then use this column in place of the primary key.
You may want to add an index to this field, but as the deleted and inserted tables in a trigger are in memory it might not get used and may have a negative effect on performance.
在触发器内部,您可以像这样使用
COLUMNS_UPDATED()
来获取更新的值,但是当您的表超过 62 列时,此代码片段会失败.. Arth.Overflow ...
这里是最终版本,它处理超过 62 列,但仅给出更新列的数量。 很容易与“syscolumns”链接来获取名称
Inside the trigger, you can use
COLUMNS_UPDATED()
like this in order to get updated valueBut this snipet of code fails when you have a table with more than 62 columns.. Arth.Overflow...
Here is the final version which handles more than 62 columns but give only the number of the updated columns. It's easy to link with 'syscolumns' to get the name
我已经将其作为简单的“一行”完成了。 没有使用、枢轴、循环、许多变量等,这使得它看起来像过程式编程。 应该使用 SQL 来处理数据集:-),解决方案是:
它使用 COLUMNS_UPDATED,处理超过八列 - 它可以处理任意数量的列。
它会注意应使用 COLUMNPROPERTY 获得的正确列顺序。
它基于视图COLUMNS,因此它可能仅包含或排除特定列。
I've done it as simple "one-liner". Without using, pivot, loops, many variables etc. that makes it looking like procedural programming. SQL should be used to process data sets :-), the solution is:
It uses COLUMNS_UPDATED, takes care of more than eight columns - it handles as many columns as you want.
It takes care on proper columns order which should be get using COLUMNPROPERTY.
It is based on view COLUMNS so it may include or exclude only specific columns.
以下代码适用于超过 64 个列,并且仅记录更新的列。 按照评论中的说明进行操作,一切都会好起来的。
The below code works for over 64 columns and logs only the updated columns. Follow the instruction in the comments and all should be well.
我将接受的答案转换为获取用逗号分隔的列名称列表(根据作者的建议)。 输出 - “Columns_Updated”为“Column1、Column2、Column5”
I transformed the accepted answer to get list of column names separated by comma (according to author's recommendation). Output - "Columns_Updated" as 'Column1,Column2,Column5'
我认为无需硬编码列名即可完成此操作的唯一方法是将已删除表的内容删除到临时表,然后根据表定义构建一个查询来比较临时表的内容和实际表,并根据它们是否匹配返回分隔列列表。 诚然,下面的内容很详细。
The only way that occurs to me that you could accomplish this without hard coding column names would be to drop the contents of the deleted table to a temp table, then build a query based on the table definition to to compare the contents of your temp table and the actual table, and return a delimited column list based on whether they do or do not match. Admittedly, the below is elaborate.
Rick 提供的示例代码缺乏对多行更新的处理。
请让我增强 Rick 的版本如下:
The sample code provided by Rick lack handling for multiple rows update.
Please let me enhance Rick's version as below: