2010-10-22 2 views
2

Итак, я создал триггер, который сравнивает обновление до и после и определяет, изменились ли определенные поля, указанные в предложении where. Если это так, я вставляю снимок предыдущей информации в таблицу истории.Сравнение полей в триггере

Проблема заключается в том, что поле создается с нулевыми значениями (с учетом бизнес-правил, оно имеет законное значение null), а когда сделано обновление, он не может оценить, что строка не равна нулевому значению. Я хочу зафиксировать, что он был отправлен нам пустым, а затем заполнен.

Какой подход следует использовать для сравнения с нулевыми полями без влияния на производительность?


Это для SQL Server 2005

CREATE TRIGGER [prj].[TRG_Master_Projection_Upd_History] ON [prj].[Master_Projections] 
AFTER UPDATE 
AS 
    SET NOCOUNT ON -- Prevents the error that gets thrown after inserting multiple records 
        -- if multiple records are being updated 

BEGIN 


INSERT INTO prj.History_Projections (ProjectionID, Cancelled, Appeal, Description, Response_PatternID, 
            Proj_Mail_date, [3602_Mail_Date], Proj_Qty, [3602_Qty], Proj_Resp_Rate, 
            Bounce_Back, Nickels, Kits, Oversized_RE, ChangeComments, 
            Modification_Process, Modification_Date, Modification_User) 
    SELECT D.ProjectionID, D.Cancelled, D.Appeal, D.Description, D.Response_PatternID, D.Proj_Mail_Date, 
      D.[3602_Mail_Date], D.Proj_Qty, D.[3602_Qty], D.Proj_Resp_Rate, D.Bounce_Back, D.Nickels, D.Kits, 
      D.Oversized_RE, D.ChangeComments, D.Modification_Process, D.Modification_Date, D.Modification_User 
     FROM deleted as D 
    JOIN inserted as I 
     ON D.ProjectionID = I.ProjectionID 
     WHERE (I.Cancelled <> D.Cancelled 
      OR I.Appeal <> D.Appeal 
      OR I.Description <> D.Description 
      OR I.Response_PatternID <> D.Response_PatternID 
      OR I.Proj_Mail_Date <> D.Proj_Mail_Date 
      OR I.[3602_Mail_Date] <> D.[3602_Mail_Date] 
      OR I.Proj_Qty <> D.Proj_Qty 
      OR I.[3602_Qty] <> D.[3602_Qty] 
      OR I.Proj_Resp_Rate <> D.Proj_Resp_Rate 
      OR I.Bounce_Back <> D.Bounce_Back 
      OR I.Nickels <> D.Nickels 
      OR I.Kits <> D.Kits 
      OR I.Oversized_RE <> D.Oversized_RE) 
END; 
SET NOCOUNT OFF; 

ответ

3

К сожалению, вы действительно должны использовать сторожевое значение

ISNULL(I.Response_PatternID, 0) <> ISNULL(D.Response_PatternID, 0) 

Там нет магии, к сожалению, вы должны сравнить каждое значение, чтобы увидеть любого различия.

Сказав, что вы только касаетесь таблиц INSERTED и DELETED так плохо, как это, основная таблица не трогается. Если у вас есть обновление, которое влияет на 10000s, если строки, оно будет работать нормально.

Вы можете использовать OR тоже, но это громоздко

(I.Response_PatternID <> D.Response_PatternID OR I.Response_PatternID IS NULL AND I.Response_PatternID IS NOT NULL OR I.Response_PatternID IS NOT NULL AND I.Response_PatternID IS NULL) 

Я бы придерживаться ISNULL, чтобы избежать тонких проблем типов данных с COALESCE

+0

работает как шарм. Не был уверен, что коалесценция была вариантом или нет, но это, похоже, это исключает. Благодаря! – Mohgeroth

+0

также, с вашим isnull's, убедитесь, что второе значение - это то, что не появится. Например, ваши личности все начинаются с 1. Затем в ваших isnulls вы можете положить что-то вроде -9999. Таким образом, если запись обновляется с идентификатором нуля, вы получаете правильную логику. – DForck42

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