1

我要做的是找出哪些字段已更新并将更改记录到另一个表中。

DECLARE 
    @BillNo int,
    @column_name varchar(500)  

SELECT @BillNo = BillNo FROM INSERTED
DECLARE HistoryMonitorLoop CURSOR FOR
    SELECT    
        column_name 
    FROM 
        information_schema.columns
    WHERE 
        table_name = 'Shipment';
OPEN HistoryMonitorLoop
FETCH next FROM HistoryMonitorLoop INTO @column_name
WHILE @@Fetch_status = 0
BEGIN
    DECLARE
        @OldValue varchar(500),
        @NewValue varchar(500)
    SET @OldValue = (SELECT @column_name FROM Deleted);
    SET @NewValue = (SELECT @column_name FROM Inserted);
    IF(@OldValue != @NewValue)
    BEGIN
        DECLARE @Comment varchar(5000)
        SELECT @Comment = @column_name + ' Changed from ' + @OldValue + ' to ' + @NewValue
        EXEC ShipmentNote_Insert @BillNo=@BillNo,@CoordinatorID=1,@Comment=@Comment
    END
    FETCH next FROM HistoryMonitorLoop INTO @column_name
END
CLOSE HistoryMonitorLoop
DEALLOCATE HistoryMonitorLoop

正在发生的事情是

SET @OldValue = (SELECT @column_name FROM Deleted);   
SET @NewValue = (SELECT @column_name FROM Inserted); 

正在将@OldValueand @NewValue= 设置为列名而不是列的值 - sql 将其处理为SET @OldValue = (SELECT 'column_name' FROM Deleted);

4

4 回答 4

3

我想做的是找出更新了哪些字段

在 SQL Server 中,有两个函数可以完全满足您的需求。

  • Columns_Updated() - 检查是否在触发器中插入/删除了一个或多个列
  • Update() - 检查触发器内是否更新了单个列
于 2009-04-14T02:24:32.590 回答
1

See this Pop on the Audit Trail 它使用循环中的查询而不是游标来执行您想要执行的操作。

于 2009-04-14T02:48:09.163 回答
0

这行不通:

SET @OldValue = (SELECT @column_name FROM Deleted);
SET @NewValue = (SELECT @column_name FROM Inserted);

您在这里尝试动态 sql,但这是行不通的。您必须对 SQL 进行硬编码,变量@column_name不会被其值动态替换,因为触发器的 SQL 在触发器运行之前被解析一次。有了这个,你(取决于你的设置)可能会得到列名的字面值。

可以获得动态 SQL(通过在另一个进程连接到服务器,或在 MySQl 中通过创建准备好的语句),但不可能这样做引用触发器中可用的“魔术”INSERTEDDELETED伪表。

所以你巧妙地使用 information_schema.columns 是行不通的。您可以做的是利用这种聪明才智编写存储过程来生成触发器(这实际上是我在编写审计触发器时所做的)。然后,每当您更改Shipment表时,您都必须运行 sp 以生成“create trigger....”statmentnt,然后运行生成的语句以重新创建触发器。

于 2009-04-13T23:23:40.887 回答
0

我会重新考虑你的整个过程。如果编写不当,触发器可能会成为巨大的性能杀手。每当您认为需要使用游标或循环时,请三思。您需要以基于集合的方式执行此操作。

我们使用两表触发方法。一个记录有关何时和谁更改表的详细信息以及包含已更改信息的相关表。这有助于我们查看一次更改的所有记录。我们为每个字段使用更新的语句来填充第二个表,例如:

if (update([test]))
  begin
    insert [myAudit].dbo.[mytableAuditLogDetail](AuditLogID, ID, ColumnName,   
                                                 OldValue, NewValue)
    select
      @AuditLogID,
      i.[mytableid]),
      'test',
      convert(varchar(8000), d.[test], 0),
      convert(varchar(8000), i.[test], 0)
    from  inserted i
    inner join deleted d on i.[mytableid]=d.[mytableid]
      and (
      (i.[test] <> d.[test]) or 
      (i.[test] is null and d.[test] Is Not Null) or
      (i.[test] is not null and d.[test] Is Null)
          )         
   end

每次模式更改时,我们都会动态重建触发器代码,但触发器本身不是动态的。即使我们进行大量导入,我们的触发过程也运行得非常快。

于 2009-04-14T14:15:42.087 回答