MSSQL有效触发INSTEAD OF INSERT

时间:2016-11-22 16:17:33

标签: sql-server tsql triggers database-trigger

我有一个使用替代插入触发器的情况。我的同事和我想知道哪一个更有效(内存使用,运行时间等)。

触发器检查记录是否存在于表中,如果没有插入新行,否则按其键更新现有行。此示例中的主键是(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中运行事务中的TRY-CATCH实现,因此需要回滚到保存点。

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

1 个答案:

答案 0 :(得分:1)

在触发器中使用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;