История на основе триггера - PullRequest
1 голос
/ 14 апреля 2009

Я пытаюсь выяснить, какие поля были обновлены, и записать изменение в другую таблицу.

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); 

устанавливает @OldValue и @NewValue = для имени столбца вместо значения столбца - sql обрабатывает его как SET @OldValue = (SELECT 'column_name' FROM Deleted);

Ответы [ 4 ]

3 голосов
/ 14 апреля 2009

Я пытаюсь выяснить, какие поля были обновлены

В SQL Server есть две функции, которые выполняют именно то, что вы ищете.

  • Columns_Updated () - Проверить, вставлены / удалены один или несколько столбцов в триггере
  • Update () - Проверить, обновляется ли один столбец в триггере
1 голос
/ 14 апреля 2009

См. Это Всплывающее окно в журнале аудита Он использует запрос в цикле, а не курсор, чтобы делать то, что вы хотите.

0 голосов
/ 14 апреля 2009

Я бы переосмыслил весь ваш процесс. Триггеры могут быть причиной значительного снижения производительности, если они написаны неправильно. Каждый раз, когда вы думаете, что вам нужно использовать курсор или цикл, подумайте еще раз. Вы должны сделать это на основе набора.

Мы используем триггерный подход с двумя таблицами. Тот, который записывает подробности о том, когда и кто изменил таблицу, и связанную таблицу, которая содержит информацию, которая была изменена. Это помогает нам увидеть все записи, которые были изменены за один раз. Мы используем обновленный оператор для каждого поля, чтобы заполнить вторую таблицу примерно так:

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

Мы перестраиваем код триггера динамически каждый раз, когда меняется схема, но сам триггер не является динамическим. Наш триггерный процесс выполняется очень быстро, даже когда мы выполняем большой импорт.

0 голосов
/ 14 апреля 2009

Это не сработает:

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

Вы пытаетесь динамический sql здесь, который не будет работать. Вы должны жестко закодировать SQL, переменная @column_name не будет динамически заменена на ее значение, потому что SQL триггера анализируется один раз, до запуска триггера. При этом вы (в зависимости от настроек), вероятно, получите буквальное значение имени столбца.

возможно получить динамический SQL (путем подключения к серверу в другом процессе или в MySQl путем создания подготовленного оператора), но это невозможно сделать и ссылаться на «магические» псевдотаблицы INSERTED и DELETED, доступные в триггере.

Так что ваше умное использование information_schema.columns не будет работать. То, что вы можете сделать, - это использовать эту хитрость, чтобы написать хранимую процедуру для генерации триггера (это фактически то, что я делал, когда мне приходилось писать триггеры аудита). Затем, когда вы изменяете таблицу Shipment, вам нужно будет запустить sp, чтобы сгенерировать statmentnt «создать триггер ....», а затем запустить , который сгенерировал инструкцию, чтобы заново создать триггер.

...