2016-11-22 63 views
0

我有一种情况需要使用不是插入触发器。我的同事和我想知道哪一个更有效(内存使用率,运行时间等)。MSSQL有效触发器INSTEAD OF INSERT

触发器检查记录是否存在于表中,如果没有插入新行,则使用其键更新现有行。本例中的主键是(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实现。

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

+3

听说过的[MERGE](https://msdn.microsoft.com/en-我们/库/ bb510625.aspx)?如果不存在则插入,如果存在则更新。不需要所有的检查。 – xQbert

+0

@xQbert我也是'MERGE'的粉丝,仍然在使用它,但我认为应该让这篇文章知道。我发现它教育。 https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ – scsimon

+0

正如其他人所说,使用合并,但绝对不使用第二个变种 - 你不应该使用这种逻辑的异常处理。你正在假设你为什么进入catch块。 –

回答

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; 
相关问题