MSSQL 有效触发器 INSTEAD OF INSERT

MSSQL effective trigger INSTEAD OF INSERT

我有一个案例需要使用 instead-of-insert 触发器。我和我的同事想知道哪个更有效(内存使用、达到 运行 的时间等)。

触发器检查table中是否存在记录,如果不存在则插入新行,否则通过其键更新现有行。此示例中的主键是 (DocumentId, VatRate) 的组合键。

第一个变体是检查记录是否已经存在:

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;

第二个变体尝试插入,如果插入失败,则更新如下:

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;

注意:需要回滚到保存点,因为 TSQL 中 运行ning 事务中的 TRY-CATCH 实现。

哪个更好,为什么?如果您有更好的解决方案,请分享。

按照此处的说明在触发器中使用 MERGE:

MERGE SYNTAX

代码示例:

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;