动态检查触发器中的旧值和新值

时间:2014-03-27 16:14:48

标签: sql sql-server tsql sql-server-2008-r2

Sql Server 2008 R2

我正在开发一个需要从触发器构建更新/插入/删除语句的同步过程。我并不担心插入或删除,我对更新有疑问。

我想/想要做的是比较更新过程中生成的每列的旧值和新值。只有更改的列,我是否要将它们包含在我的同步脚本中。

嗯,经过一些挖掘和测试,我的问题实际上归结为:我正在尝试执行此声明并且它说它不识别'插入'。有没有不同的方法来做到这一点?

Set @sqlText = 'Insert Into ##changedColumns (ColumnName, NewValue, PrimaryKey) Select ''' + @column + ''', i.' + @column + ', i.' + @primaryKeyColumn + ' From inserted i Inner Join deleted d On d.' + @primaryKeyColumn + ' = i.' + @primaryKeyColumn + ' Where i.' + @column + ' <> d.' + @column

Exec(@sqlText)

2 个答案:

答案 0 :(得分:1)

由于这是您采取的路线,我将发表评论作为答案

即使你开始工作,你也会在每个触发器中都有一个光标 硬编码触发器将更有效。

答案 1 :(得分:0)

根据之前编辑的问题,我认为这样的事情可能就是你想要的:

-- sample table
CREATE TABLE [tableA]
(
  TableAId int identity(1,1) PRIMARY KEY,
  Column1 int not null,
  Column2 int null,
  Column3 varchar(50) null
)
GO
-- procedure to create sync trigger on target table
CREATE PROCEDURE [dbo].[CreateSyncTrigger]
    @table_name NVARCHAR(128)
AS

DECLARE @sql NVARCHAR(MAX);
SET @sql = 'CREATE TRIGGER [mySyncTrigger_' + @table_name + '] ON ' + QUOTENAME(@table_name) + ' 
AFTER UPDATE
AS 
' + (
SELECT
    CHAR(10) + 'IF UPDATE(' + QUOTENAME([COLUMN_NAME]) + ')
    INSERT INTO ##changedColumns([ColumnName], [NewValue], [PrimaryKey])
    SELECT ''' + [COLUMN_NAME] + ''', I.' + QUOTENAME([COLUMN_NAME]) + ', I.' + QUOTENAME([pk_column_name]) + '
    FROM INSERTED I
    INNER JOIN DELETED D
    ON      I.' + QUOTENAME([pk_column_name]) + ' = D.' + QUOTENAME([pk_column_name]) + '
    WHERE I.' + QUOTENAME([COLUMN_NAME]) + ' != D.' + QUOTENAME([COLUMN_NAME]) + CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS X
CROSS JOIN ( -- get primary key col
    SELECT 
        D.[name] [table_name],
        C.[name] [pk_column_name]
    FROM sys.indexes A
    INNER JOIN sys.index_columns B
    ON      A.[object_id] = B.[object_id]
        AND A.[index_id] = B.[index_id]
    INNER JOIN sys.columns C
    ON      B.[object_id] = C.[object_id]
        AND B.[column_id] = C.[column_id]
    INNER JOIN sys.tables D
    ON      C.[object_id] = D.[object_id]
    WHERE   A.[is_primary_key] = 1 
        AND D.[name] = @table_name
) Y
WHERE   X.[table_name] = @table_name
    AND X.[COLUMN_NAME] != Y.[pk_column_name]
FOR XML PATH(''),TYPE
    ).value('.','NVARCHAR(MAX)');

-- create trigger on target table
EXECUTE sp_executesql @sql;
GO
-- create sample trigger
EXECUTE [CreateSyncTrigger] 'TableA'

GO
-- sample trigger output
CREATE TRIGGER [mySyncTrigger_TableA] 
ON [tableA]
AFTER UPDATE
AS

IF UPDATE ([Column1])
    INSERT INTO ##changedColumns([ColumnName], [NewValue], [PrimaryKey])
    SELECT 'Column1', I.[Column1], I.[TableAId]
    FROM INSERTED I
    INNER JOIN DELETED D
    ON I.[Column1] != D.[Column1]
    ...

GO  

运行该过程将为所提供的表名的每个非主键列创建所需的触发器。