2010-10-22 26 views
2

J'ai donc créé un déclencheur qui compare les mises à jour avant et après et détermine si des champs spécifiques, spécifiés dans la clause where, ont été modifiés. Si c'est le cas, j'insère un instantané de l'information précédente dans un tableau d'historique. Le problème est lorsque le champ est créé avec des valeurs nulles (compte tenu des règles métier, il est légitimement nul) et lorsqu'une mise à jour est faite, il est incapable d'évaluer que la chaîne n'est pas égale à la valeur nulle. Je veux capturer qu'il nous a été envoyé vide et rempli plus tard.Comparaison de champs dans un déclencheur

Quelle approche dois-je utiliser pour comparer aux champs null sans impact sur les performances?


Ceci est pour 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; 

Répondre

3

Malheureusement, vous devez vraiment utiliser des valeurs sentinelle

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

Il n'y a pas de magie, malheureusement, vous devez comparer toutes les valeurs pour voir tout différences. En disant cela, vous ne touchez que les tableaux INSERTED et DELETED, aussi mauvais que cela soit, la table principale n'est pas touchée. Sauf si vous avez une mise à jour qui affecte 10000s si lignes, il va fonctionner correctement.

Vous pouvez utiliser ou trop pour mais cela est lourd

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

Je tiens à ISNULL pour éviter les problèmes de subtiles avec COALESCE

datatype
+0

fonctionne comme un charme. Je ne savais pas si coalesce était une option ou non, mais cela semble l'exclure. Merci! – Mohgeroth

+0

également, avec votre isnull, assurez-vous que la deuxième valeur est quelque chose qui n'apparaîtra pas. Par exemple, vos identités commencent toutes à 1. alors dans vos isnulls vous pouvez mettre quelque chose comme -9999. De cette façon, si l'enregistrement est mis à jour avec un identifiant de zéro, vous obtenez la bonne logique. – DForck42