Триггер аудита для внешнего ключа

#sql-server #tsql #triggers #audit

#sql-сервер #tsql #триггеры #аудит

Вопрос:

Приведенный ниже код является триггером аудита для моей Branch таблицы. Он способен записывать любые изменения редактирования или вставки из Branch таблицы.

Однако у меня есть внешний ключ BranchZoneID к BranchZone таблице. Я хочу сделать так, чтобы любые изменения в этом внешнем ключе записывались, и чтобы он отображал BranchZoneName из BranchZone таблицы вместо BranchZoneID .

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

Триггер для BranchZoneID не работает. Что мне нужно изменить?

 create trigger Branch_Audit
on dbo.Branch
after insert, update
not for replication
as
begin
  set nocount on;

  declare @operation char(10) = case when exists (select * from deleted) then 'Edit' else 'Insert' end;

  insert AuditLog
(TableName, ModifiedBy, AuditDateTime, AuditAction, ID, ChangedColumn, OldValue, NewValue)
    select
      'Branch', suser_sname(), getdate(), @operation, I.BranchZoneID,
      'BranchName', convert(varchar(21),D.BranchName), convert(varchar(21),I.BranchName)
    from inserted I
    left outer join deleted D on I.BranchID = D.BranchID
    where coalesce(I.BranchName,'') <> coalesce(D.BranchName,'')
    and update(BranchName)
    union all

    select
    'Branch', suser_sname(), getdate(), @operation, I.BranchID,
    'BranchAddress', D.BranchAddress, I.BranchAddress
    from inserted I
    left outer join deleted D on I.BranchID = D.BranchID
    where coalesce(I.BranchAddress,'') <> coalesce(D.BranchAddress,'')
    and update(BranchAddress)
    union all


    select
    'Branch', suser_sname(), getdate(), @operation, I.BranchID,
    'BranchGeoLocationLat', D.BranchGeoLocationLat, I.BranchGeoLocationLat
    from inserted I
    left outer join deleted D on I.BranchID = D.BranchID
    where coalesce(I.BranchGeoLocationLat,'') <> coalesce(D.BranchGeoLocationLat,'')
    and update(BranchGeoLocationLat)
    union all


    select
    'Branch', suser_sname(), getdate(), @operation, I.BranchID,
    'BranchGeoLocationLong', D.BranchGeoLocationLong, I.BranchGeoLocationLong
    from inserted I
    left outer join deleted D on I.BranchID = D.BranchID
    where coalesce(I.BranchGeoLocationLong,'') <> coalesce(D.BranchGeoLocationLong,'')
    and update(BranchGeoLocationLong)
    union all

    select
    'Branch', SUSER_SNAME(), GETDATE(), @operation, I.BranchID,
    'BranchZoneID', OWD.BranchZoneName, NWD.BranchZoneName
    from inserted I
    left outer join deleted D on I.BranchID = D.BranchID
    where coalesce(I.BranchZoneID,'') <> coalesce(D.BranchZoneID,'')
    and update(BranchZoneID)
    -- Fetch Branch Zone Name
    on deleted.BranchZoneID = OWD.BranchZoneID
    join dbo.BranchZone NWD
    on inserted.BranchZoneID = NWD.BranchZoneID

end;
  

Комментарии:

1. Так в чем же проблема? Вы присоединяетесь к соответствующей таблице. Чего вы не можете сделать, так это просто «изобрести» псевдоним и ссылаться на него в своем операторе select. И для дальнейшего использования, когда ваша проблема включает ошибки, вы должны публиковать полные и фактические сообщения об ошибках. И вам действительно следует упомянуть, что ваш код генерирует ошибки, что и происходит, поскольку OWD и NWD являются псевдонимами, которые не были определены.

Ответ №1:

Вы просто перепутали со своим join… присоединяйтесь правильно, и это работает так, как задумано. И помните, что при использовании псевдонима таблицы с этого момента вы можете ссылаться на таблицу только с использованием псевдонима, например, I вместо Inserted .

Также предполагается, что BranchZoneID это int вам нужно coalesce преобразовать его в неиспользуемую, int например 0 , не пустую строку.

 select
    'Branch', suser_sname(), getdate(), @operation, I.BranchID
    , 'BranchZoneID', OWD.BranchZoneName, NWD.BranchZoneName
from inserted I
left outer join deleted D on I.BranchID = D.BranchID

-- Fetch Branch Zone Names
left join dbo.BranchZone OWD on OWD.BranchZoneID = D.BranchZoneID
left join dbo.BranchZone NWD on NWD.BranchZoneID = I.BranchZoneID

where coalesce(I.BranchZoneID,0) <> coalesce(D.BranchZoneID,0)
and update(BranchZoneID);
  

И если BranchZoneID это uniqueidentifer , вы бы использовали:

 where coalesce(I.BranchZoneID,'00000000-0000-0000-0000-000000000000') <> coalesce(D.BranchZoneID,'00000000-0000-0000-0000-000000000000')
  

При использовании coalesce для сравнения значений таким образом вам необходимо выбрать значение, которое допустимо для типа данных, но которое недопустимо в ваших данных.

Комментарии:

1. Привет, если BranchZoneID является уникальным идентификатором, на что мне нужно изменить ‘0’ в (I.BranchZoneID, 0)?

2. Когда я пытаюсь отредактировать BranchZoneID на моем веб-сайте, появляется эта ошибка: «SQLException: ошибка преобразования типа данных nvarchar в числовой».

3. Типом данных ‘oldValue’ и ‘newValue’ является Nvarchar(250). Однако я сомневаюсь, что мне нужно менять его тип данных.

4. Я не вижу, как это могло бы произойти, если BranchZoneID это uniqueidentifier. Где-то у вас есть int столбец, который вы неправильно конвертируете, но, не видя ваших определений таблиц и образцов данных, я не могу предложить никаких предложений.

5. В моей таблице нет столбца int.