我有一个触发器,在更新某些列时会记录到Audit
表。我在删除列后使用columns_updated()
时遇到了很多问题,所以我只是使用Update()
重写触发器,这似乎有效。
但是,我在每个IF
语句If Update(ColumnName)
中不断重复查询,请参阅下面的代码,因为我需要动态更改列名。有没有办法欺骗这个,所以我不必继续重复INSERT
查询?
IF (@TYPE IN ('U') and UPDATE(ShippingAddressFlag))
BEGIN
SELECT @fieldname = 'ShippingAddressFlag'
SELECT @SQL = 'insert Audit (Type, TableName, PKCol, PK, FieldName, OldValue, NewValue, UpdateDate, DBUserName, UserID)'
SELECT @SQL = @SQL + ' select ''' + @TYPE + ''''
SELECT @SQL = @SQL + ',''' + @TableName + ''''
SELECT @SQL = @SQL + ',''' + @PKCol + ''''
SELECT @SQL = @SQL + ',' + @PK
SELECT @SQL = @SQL + ',''' + @fieldname + ''''
SELECT @SQL = @SQL + ',convert(varchar(1000),d.' + replace(@fieldname, '''', '') + ')'
SELECT @SQL = @SQL + ',convert(varchar(1000),i.' + replace(@fieldname, '''', '') + ')'
SELECT @SQL = @SQL + ',''' + @UpdateDate + ''''
SELECT @SQL = @SQL + ',''' + @UserName + ''''
SELECT @SQL = @SQL + ',''' + @UserID + ''''
SELECT @SQL = @SQL + ' from #ins i full outer join #del d'
SELECT @SQL = @SQL + @PKCols
SELECT @SQL = @SQL + ' where i.' + @fieldname + ' <> d.' + @fieldname
SELECT @SQL = @SQL + ' or (i.' + @fieldname + ' is null and d.' + @fieldname + ' is not null)'
SELECT @SQL = @SQL + ' or (i.' + @fieldname + ' is not null and d.' + @fieldname + ' is null)'
Print @SQL
END
IF (@TYPE IN ('U') and UPDATE(Amount))
BEGIN
SELECT @fieldname = 'Amount'
SELECT @SQL = 'insert Audit (Type, TableName, PKCol, PK, FieldName, OldValue, NewValue, UpdateDate, DBUserName, UserID)'
SELECT @SQL = @SQL + ' select ''' + @TYPE + ''''
SELECT @SQL = @SQL + ',''' + @TableName + ''''
SELECT @SQL = @SQL + ',''' + @PKCol + ''''
SELECT @SQL = @SQL + ',' + @PK
SELECT @SQL = @SQL + ',''' + @fieldname + ''''
SELECT @SQL = @SQL + ',convert(varchar(1000),d.' + replace(@fieldname, '''', '') + ')'
SELECT @SQL = @SQL + ',convert(varchar(1000),i.' + replace(@fieldname, '''', '') + ')'
SELECT @SQL = @SQL + ',''' + @UpdateDate + ''''
SELECT @SQL = @SQL + ',''' + @UserName + ''''
SELECT @SQL = @SQL + ',''' + @UserID + ''''
SELECT @SQL = @SQL + ' from #ins i full outer join #del d'
SELECT @SQL = @SQL + @PKCols
SELECT @SQL = @SQL + ' where i.' + @fieldname + ' <> d.' + @fieldname
SELECT @SQL = @SQL + ' or (i.' + @fieldname + ' is null and d.' + @fieldname + ' is not null)'
SELECT @SQL = @SQL + ' or (i.' + @fieldname + ' is not null and d.' + @fieldname + ' is null)'
Print @SQL
END
答案 0 :(得分:0)
我不确定以下内容的效果,但您可以使用unpivot
获得类似的效果
将audit
表视为
CREATE TABLE dbo.AuditLog
(
DatabaseName SYSNAME,
SchemaName SYSNAME,
TableName SYSNAME,
ColumnName SYSNAME,
KeyValue SQL_VARIANT,
OldValue SQL_VARIANT,
NewValue SQL_VARIANT,
TransactionType VARCHAR(10),
LogDate AS CURRENT_TIMESTAMP
)
GO
然后是您要记录的“普通”表
CREATE TABLE dbo.MyTable
(
Id INT IDENTITY(1,1),
Col1 INT,
Col2 INT,
Col3 INT
)
GO
使用unpivot
记录更改的触发器将是
ALTER TRIGGER dbo.trg_MyTable_AuditLog
ON dbo.MyTable
FOR INSERT, UPDATE, DELETE
NOT FOR REPLICATION
AS
BEGIN
DECLARE @DATABASENAME SYSNAME = DB_NAME(),
@TABLENAME SYSNAME = N'MyTable',
@SCHEMANAME SYSNAME = N'dbo',
@INSERTED SMALLINT = 1,
@DELETED SMALLINT = 2,
@UPDATED SMALLINT = 3
DECLARE @action SMALLINT = 0
SELECT @action = CASE WHEN EXISTS(SELECT 1 FROM inserted) THEN @INSERTED ELSE 0 END +
CASE WHEN EXISTS(SELECT 1 FROM deleted) THEN @DELETED ELSE 0 END
IF @action = @INSERTED
BEGIN
INSERT INTO dbo.AuditLog (DatabaseName, SchemaName, TableName, ColumnName, KeyValue, OldValue, NewValue, TransactionType)
SELECT @DATABASENAME, @SCHEMANAME, @TABLENAME, ColumnName, Id, NULL, NewValue, 'INSERT'
FROM inserted
UNPIVOT (
NewValue
FOR ColumnName IN ( Col1, Col2 )
) upiv
END
IF @action = @DELETED
BEGIN
INSERT INTO dbo.AuditLog (DatabaseName, SchemaName, TableName, ColumnName, KeyValue, OldValue, NewValue, TransactionType)
SELECT @DATABASENAME, @SCHEMANAME, @TABLENAME, ColumnName, Id, OldValue, Null, 'DELETE'
FROM deleted
UNPIVOT (
OldValue
FOR ColumnName IN ( Col1, Col2 )
) upiv
END
IF @action = @UPDATED
BEGIN
INSERT INTO dbo.AuditLog (DatabaseName, SchemaName, TableName, ColumnName, KeyValue, OldValue, NewValue, TransactionType)
SELECT @DATABASENAME, @SCHEMANAME, @TABLENAME, upiv_inserted.ColumnName,
upiv_inserted.Id, upiv_deleted.OldValue, upiv_inserted.NewValue, 'UPDATE'
FROM (
SELECT ColumnName, Id, NewValue
FROM inserted
UNPIVOT (
NewValue
FOR ColumnName IN ( Col1, Col2 )
) upiv
) upiv_inserted
JOIN (
SELECT ColumnName, Id, OldValue
FROM deleted
UNPIVOT (
OldValue
FOR ColumnName IN ( Col1, Col2 )
) upiv
) upiv_deleted
ON upiv_deleted.Id = upiv_inserted.Id
AND upiv_deleted.ColumnName = upiv_inserted.ColumnName
WHERE upiv_deleted.OldValue <> upiv_inserted.NewValue
END
END
GO
要执行此操作,不透视的列必须是相同的数据类型,因此您可能需要添加一些派生表,并根据需要添加列。
同样,unpivot
似乎对varchar
和排序规则的长度敏感,一个更好的解决方案,然后取消汇总派生表将使用cross apply
而不是{{1} }。 unpivot
似乎与字符串长度没有相同的“敏感性”,并且可以更简洁地将表达式应用于列。
这意味着将之前的支点改为
cross apply
编辑评论:
INSERT INTO dbo.AuditLog (DatabaseName, SchemaName, TableName, ColumnName, KeyValue, OldValue, NewValue, TransactionType)
SELECT @DATABASENAME, @SCHEMANAME, @TABLENAME, ColumnName, Id, OldValue, Null, 'DELETE'
FROM deleted
CROSS APPLY (
VALUES
('Col1', Col1),
('Col2', Col2)
) upiv (ColumnName, OldValue)