1

我在 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;

有没有更简单的方法来实现这一点?

4

2 回答 2

2

就在这里。
您可以使用该COLUMNS_UPDATED函数来确定实际更改了值的列,尽管它在代码可读性方面不是一个非常友好的函数。
阅读Microsoft 支持的这篇文章,名为正确使用 COLUMNS_UPDATED() 函数,了解我的意思。

我遇到了一篇名为A More Performant Alternative To COLUMNS_UPDATED()的文章,也许它可以帮助您或至少启发您。

我会注意,您应该抵制使用该UPDATE()函数的诱惑,因为即使没有更改任何数据,它也可能返回 true。
这是来自它的 MSDN 页面的相关部分:

无论 INSERT 或 UPDATE 尝试是否成功,UPDATE() 都返回 TRUE。

于 2015-05-27T14:54:49.813 回答
1

看起来您正在尝试构建一个动态解决方案,如果您希望经常更改(=要添加的新列等),这可能会很有用。你可以做这样的事情(在伪代码中)

为列名构建基于 DMV (INFORMATION_SCHEMA.COLUMNS) 的动态 SQL:

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 的 delimited_split_8k ( http://www.sqlservercentral.com/articles/Tally+Table/72993/ )。

同样正如 Damien 指出的那样,插入/删除的表中可以有不止一行。

于 2015-05-27T15:03:56.277 回答