2009-04-13 6 views
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 @[email protected],@CoordinatorID=1,@[email protected] 
    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 = к ColumnName вместо значения столбца - SQL обрабатывает его как SET @OldValue = (SELECT 'column_name' FROM Deleted);

+0

Итак, работает ли скрипт? Вы получаете ошибки? Вы просто спрашиваете, кажется ли это нормально, прежде чем вы его протестируете? – BradC

+0

и ?, в чем вопрос? –

+0

Что происходит SET @OldValue = (SELECT @column_name FROM Deleted); SET @NewValue = (SELECT @column_name FROM Inserted); устанавливают @OldValue и @NewValue = для имени столбца вместо значения столбца –

ответ

1

Смотрите эту Pop on the Audit Trail Он использует запрос в цикле, а не курсор, чтобы сделать то, что вы хотите сделать.

+0

, который сделал это, теперь все, что мне нужно сделать, это выяснить, как;) –

0

Это не будет работать :

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

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

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

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

+0

ShipmentNote_Insert добавляет в datestamp, так что это не проблема. поскольку производительность попадает в данные в таблице отгрузки, сама не обновляется часто, но когда это нужно, нам нужно знать, что было изменено, приложение сторонних разработчиков использует уведомления. структура таблицы очень текучая прямо сейчас –

+0

Итак, как вы думаете? – tpdi

3

То, что я пытаюсь сделать, это выяснить, какие поля были обновлены

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

  • Columns_Updated() - Проверьте, если один или более столбец (и)/вставляются/удаляются в триггере
  • Update() - Проверьте, если один столбец обновляется в триггере
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 

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

Смежные вопросы