2016-11-22 5 views
0

J'ai un cas où l'utilisation du déclencheur à la place de l'insertion est nécessaire. Mes collègues et moi nous demandons lequel est le plus efficace (utilisation de la mémoire, temps de fonctionnement, etc.).Déclencheur actif MSSQL AU LIEU DE L'INSÉRER

Le déclencheur vérifie si l'enregistrement existe dans la table, si aucun n'insère la nouvelle ligne, sinon met à jour la ligne existante par sa clé. La clé primaire de cet exemple est la clé composite de (DocumentId, VatRate).

La première variante est de vérifier si le dossier existe déjà:

CREATE TRIGGER docvatsum_trg 
ON DocumentVatSummary 
INSTEAD OF INSERT 
AS 
BEGIN 
     IF EXISTS (
     SELECT 1 FROM DocumentVatSummary a 
     JOIN inserted b ON (a.DocumentId = b.DocumentId AND a.VatRate = b.VatRate) 
    ) 
     BEGIN 
     UPDATE DocumentVatSummary 
     SET 
      DocumentVatSummary.VatBase = i.VatBase, 
      DocumentVatSummary.VatTotal = i.VatTotal 
     FROM inserted i 
     WHERE 
      DocumentVatSummary.DocumentId = i.DocumentId AND 
      DocumentVatSummary.VatRate = i.VatRate 
     END 
     ELSE 
     BEGIN 
     INSERT INTO DocumentVatSummary 
     SELECT * FROM inserted 
     END 
END; 

La deuxième variante tente d'insérer et si insertion échoue une mise à jour suit:

CREATE TRIGGER docvatsum_trg 
ON DocumentVatSummary 
INSTEAD OF INSERT 
AS 
BEGIN 
    SAVE TRANSACTION savepoint 
    BEGIN TRY 
     INSERT INTO DocumentVatSummary 
     SELECT * FROM inserted 
    END TRY 
    BEGIN CATCH 
     IF XACT_STATE() = 1 
     BEGIN 
      ROLLBACK TRAN savepoint 

      UPDATE DocumentVatSummary 
      SET 
       DocumentVatSummary.VatBase = i.VatBase, 
       DocumentVatSummary.VatTotal = i.VatTotal 
      FROM inserted i 
      WHERE 
       DocumentVatSummary.DocumentId = i.DocumentId AND 
       DocumentVatSummary.VatRate = i.VatRate 
     END 
    END CATCH 
END; 

Note: Rollback à savepoint est requis, en raison de l'implémentation de TRY-CATCH lors de l'exécution de la transaction dans TSQL.

Lequel est le meilleur et pourquoi? Si vous avez une meilleure solution, s'il vous plaît partager.

+3

jamais entendu parler de ([Merge] https://msdn.microsoft.com/en- us/library/bb510625.aspx)? insérera s'il n'existe pas et mettra à jour s'il existe. Pas besoin de toutes les vérifications. – xQbert

+0

@xQbert Je suis aussi fan de 'MERGE' et je l'utilise encore mais je pense que cet article devrait être mis au courant. Je l'ai trouvé éducatif. https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ – scsimon

+0

Comme d'autres l'ont dit, utilisez la fusion, mais n'utilisez certainement pas la deuxième variante - vous ne devriez pas utiliser la gestion des exceptions pour ce type de logique. Vous faites une supposition sur la raison pour laquelle vous êtes entré dans le bloc catch. –

Répondre

1

Utilisez votre déclencheur MERGE comme expliqué ici:

MERGE SYNTAX

Exemple de code:

DECLARE @SummaryOfChanges TABLE(Change VARCHAR(20)); 

MERGE INTO Sales.SalesReason AS Target 
USING (VALUES ('Recommendation','Other'), 
       ('Review', 'Marketing'), 
       ('Internet', 'Promotion')) 
     AS Source (NewName, NewReasonType) 
ON Target.Name = Source.NewName 
WHEN MATCHED THEN 
UPDATE SET ReasonType = Source.NewReasonType 
WHEN NOT MATCHED BY TARGET THEN 
INSERT (Name, ReasonType) VALUES (NewName, NewReasonType) 
OUTPUT $action INTO @SummaryOfChanges;