我在mssql中有一个触发器,我想在其中将插入表中的每一列与已删除的表进行比较以检查值是否已更改... 如果值已更改,我想将列名插入临时表。
我的代码到现在为止:
declare columnCursor CURSOR FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable' AND TABLE_SCHEMA='dbo'
--save inserted and deleted into temp tables
select * into #row1 from Inserted
select * into #row2 from Deleted
declare @tmp table(column_name nvarchar(max))
declare @column nvarchar(50)
OPEN COlumnCUrsor
FETCH NEXT FROM ColumnCursor INTO @column
while @@FETCH_STATUS=0 begin
declare @out bit
declare @sql nvarchar(max) = N'
select @out = case when r1.'+@column+'r2.'+@column+' then 1 else 0 end
from #row1 r1
left join #row2 r2 on r1.sys_volgnr=r2.sys_volgnr'
exec sp_executesql @sql,N'@out bit OUTPUT', @out=@out OUTPUT
if( @out = 1 ) begin
insert into @tmp VALUES(@column)
end
FETCH NEXT FROM ColumnCursor INTO @column
end
CLOSE ColumnCursor;
DEALLOCATE ColumnCursor;
有没有更简单的方法来实现这一目标?
答案 0 :(得分:2)
是的,有。
您可以使用COLUMNS_UPDATED
函数来确定实际更改值的列,但就代码可读性而言,它不是一个非常友好的函数。
从Microsoft支持中读取this article,称为正确使用COLUMNS_UPDATED()函数,看看我的意思。
我发现了一篇名为A More Performant Alternative To COLUMNS_UPDATED()的文章,也许它可以帮助你或至少激励你。
我会注意到你应该抵制使用UPDATE()
函数的诱惑,因为即使没有数据被更改,它也可能会返回true。
这是MSDN页面的相关部分:
无论INSERT或UPDATE尝试是否成功,UPDATE()都返回TRUE。
答案 1 :(得分:1)
您似乎正在尝试构建动态解决方案,如果您希望经常更改(=要添加的新列等),这可能很有用。你可以这样做(伪代码)
为列名构建基于DMV的动态SQL(INFORMATION_SCHEMA.COLUMNS):
insert into table ...
select
function_to_split_by_comma (
case when I.col1 = U.col1 then 'col1,' else '' end +
case when I.col2 = U.col2 then 'col2,' else '' end +
...
)
where
I.key_column1 = U.key_column1 ...
这些名称(col1,col2)应该是DMV查询中的列,+每行的大小写,然后是开头的固定SQL部分+你需要弄清楚如何连接插入并删除,这需要主键。
为了将数据拆分成行,您可以使用例如Jeff Moden(http://www.sqlservercentral.com/articles/Tally+Table/72993/)的delimited_split_8k。
同样Damien指出,插入/删除表中可以有多行。