Я внедрил структуру журнала аудита на основе информации, предоставленной в первом ответе на следующее сообщение:
Таблица истории SQL Server - заполнить с помощью SP или Trigger?
В конечном счете, реализованная мной среда использует три триггера для каждой таблицы, которые вставляют информацию аудита на основе изменений в таблицах.
Мои триггеры аудита вставки и удаления довольно просты.Однако триггеры обновления намного сложнее, потому что триггер должен проверить, чтобы определить, находится ли каждый столбец под контролем аудита, а затем выполнить вставку, основываясь на том, равны ли значения столбцов в столбцах «Вставлено» и «Удалено» или нет, посколькуЯ не хочу писать ненужные записи аудита.В конечном счете, я хочу знать, есть ли способ написать хранимую процедуру, которая уменьшит объем кода в моем триггере, позволяя мне динамически выполнять оператор вставки ниже.По сути, я представляю триггер, запускающий sproc с каждым именем столбца, которое находится под контролем аудита, и затем хранимая процедура будет использовать имя столбца для выполнения фрагмента кода ниже.В настоящее время у меня есть код ниже для каждого столбца, который находится под контролем аудита, что, к сожалению, приводит к большому количеству избыточного кода.
Пересмотренный триггер после предложенных изменений
CREATE TRIGGER [dbo].[Audit_Customers_Update] ON [dbo].[Customers]
FOR UPDATE AS
select FirstName,LastName into #deleted from deleted;
declare /*const*/ @TABLE_NAME sysname = '[table name]';
declare f cursor
local
forward_only
read_only
for
select c.name, quotename(c.name, '[')
from
sys.columns c
inner join sys.types t on c.system_type_id = t.system_type_id
where
c.object_id = object_id(@TABLE_NAME)
and c.is_computed = 0
and c.is_identity = 0
and t.name not in ('text', 'image', 'timestamp', 'xml')
and (substring(COLUMNS_UPDATED(), ((c.column_id - 1) / 8) + 1, 1) & power(2, (c.column_id - 1) % 8)) > 0
;
declare @field_name sysname, @field_name_sanitised sysname;
create table #results (row_id int not null,
field_name sysname not null,
oldval nvarchar(150) null,
newval nvarchar(150) null);
-- For each changed field, insert what exactly changed into #results
open f;
fetch next from f into @field_name, @field_name_sanitised;
while @@fetch_status = 0
begin
declare @query nvarchar(4000);
set @query = N'insert into #results(row_id, field_name, oldval, newval)
select d.row_id, @field_name, d.' + @field_name_sanitised + N', i.' + @field_name_sanitised + N'
from
#deleted d inner join ' + @TABLE_NAME + N' i on d.row_id = i.row_id
where
(d.' + @field_name_sanitised + N' <> i.' + @field_name_sanitised + N')
or
(case when d.' + @field_name_sanitised + N' is null then 1 else 0 end <> case when i.' + @field_name_sanitised + N' is null then 1 else 0 end);'
;
exec sp_executesql
@stmt = @query,
@params = N'@field_name sysname',
@field_name = @field_name
;
fetch next from f into @field_name, @field_name_sanitised;
end;
close f;
deallocate f;
-- Do something meaningful to #results here
Как получить доступ к #results?Нужно ли использовать курсор?