2010-10-26 64 views
2

我想插入到使用select,但我知道有些行可能會失敗(這是預期的)。有沒有辦法更改SQL Server 2008的隱式事務,以便沒有失敗的事件不會回滾?關閉隱式事務

-- get the count of the customers to send the sms to 
SELECT @count = COUNT(*) 
FROM PreCampaignCustomer 
WHERE Processed = 0 AND CampaignID = @campaignid 
AND ErrorCount < 5 

WHILE (@count > 0) 
BEGIN 
    DECLARE @customerid INT, 
      @carrierid INT, 
      @merchantcustomerid INT, 
      @smsnumber NVARCHAR(50), 
      @couponcode NVARCHAR(20) 

    SELECT TOP 1 @customerid = pcc.CustomerID, @merchantcustomerid = pcc.MerchantCustomerID, 
    @carrierid = c.CarrierID, @smsnumber = c.SMSNumber 
    FROM PreCampaignCustomer pcc 
    INNER JOIN Customer c ON c.ID = pcc.CustomerID 
    WHERE pcc.Processed = 0 AND pcc.CampaignID = @campaignid 
    AND pcc.ErrorCount < 5 
    ORDER BY pcc.ErrorCount 

    --set the couponcode  
    IF @couponlength = -1 
    BEGIN 
     SET @couponcode = 'NOCOUPON' 
    END 
    ELSE 
    BEGIN 
     EXEC [GenerateCouponCode] 
     @length = 9, 
     @couponcode = @couponcode OUTPUT 
    END 

    BEGIN TRY 
     --use try/catch just in case the coupon code is repeated or any other error 

     --Set the coupon text 
     DECLARE @coupontext NVARCHAR(200), 
       @smsrequestxml XML 


     IF @coupontypecode = 1 --NONE 
     BEGIN 
      SET @coupontext = @merchantname + ': ' + @smsmessage + ', Use Code: ' + dbo.FormatCouponCode(@couponcode, @couponcodegrouping) + '. Reply STOP to quit' 
     END 
     ELSE 
     BEGIN 
      SET @coupontext = @merchantname + ': ' + @smsmessage + '. Reply STOP to quit' 
     END 

     EXEC GetSMSRequest @config = @smsconfig, 
        @smsType = 1, --Submit 
        @address = @smsnumber, 
        @carrierID = @carrierid, 
        @message = @coupontext, 
        @xml = @smsrequestxml OUTPUT 

     BEGIN TRAN 
      --create the CampaignCustomer record 
      INSERT INTO CampaignCustomer 
      (CampaignID, CustomerID, CouponCode, Active) 
      VALUES 
      (@campaignid, @customerid, @couponcode, 1) 

      --Add the record to the queue 
      INSERT INTO SMSQueue 
      (CarrierID, [Address], [Message], TimeToSend, RequestXML, QueueID, HTTPStatusCode, Retries) 
      VALUES 
      (@carrierid, @smsnumber, @coupontext, @timetosend, @smsrequestxml, @queueid, 0, 0) 

      --Create Outgoing SMS Log 
      INSERT INTO SMSOutgoingLog 
      (MerchantID, MerchantGroupID, MessageTypeCode, CreatedDate, Active) 
      VALUES 
      (@merchantid, @merchantgroupid, @messagetypecode, GETDATE(), 1) 

      --Update the LastSentSMSTime of the MerchantCustomer 
      UPDATE MerchantCustomer 
      SET LastSentSMS = GETDATE(), 
      ModifiedDate = GETDATE() 
      WHERE ID = @merchantcustomerid 

      UPDATE PreCampaignCustomer 
      SET Processed = 1, 
      ModifiedDate = GETDATE() 
      WHERE CustomerID = @customerid 
      AND CampaignID = @campaignid 
     COMMIT TRAN 
    END TRY 
    BEGIN CATCH 
     ROLLBACK TRAN 

     -- Set the error 
     UPDATE PreCampaignCustomer 
     SET ErrorCount = ErrorCount + 1, 
     ModifiedDate = GETDATE(), 
     ErrorMessage = ERROR_MESSAGE(), 
     ErrorNumber = ERROR_NUMBER() 
     WHERE CustomerID = @customerid 
     AND CampaignID = @campaignid 
    END CATCH 

    SELECT @count = COUNT(*) 
    FROM PreCampaignCustomer 
    WHERE Processed = 0 AND CampaignID = @campaignid 
    AND ErrorCount < 5 
END 

回答

2

不,INSERT是一個命令。事務處理控制多個命令如何組合成單個工作單元,而不是如何將行組合在一個命令中。你不能有一些行INSERT和那些失敗(一些約束問題),只是被忽略。如果有任何行失敗,那麼整個INSERT失敗。

爲什麼不嘗試修改SELECT來排除將失敗的行?

類似:

INSERT INTO YourTable 
     (col1, col2, col3) 
    SELECT 
     colA, colB, ColC 
     FROM YourOtherTable 
     WHERE ColA NOT IN (SELECT col1 FROM YourTable) 
+0

我爲每一行生成一個隨機優惠券代碼,並且對優惠券代碼有一個唯一的約束。而不是做一個select來查看它是否存在我讓SQL Server處理約束並讓它失敗。您認爲使用該優惠券代碼檢查計數(*)會更快嗎? – 2010-10-26 14:33:16

+0

你循環,每次迭代一次插入?如果是的話發佈代碼,以便我可以看到究竟發生了什麼。有辦法生成一組隨機數字:http://stackoverflow.com/questions/183124/multiple-random-values-in-sql-server-2005/183183#183183。 COUNT(*)也很慢(它工作更多),而不僅僅是一個普通的EXISTS。 – 2010-10-26 14:42:21

+0

是的,我正在循環。我添加了代碼。底線我需要使這個查詢儘可能高效。也許不是每次迭代都要計數,只需執行select top 1,然後WHILE NOT @customerid爲null。還有其他建議嗎? – 2010-10-26 15:10:26

0

它可以控制使用SET XACT_ABORT OFF(ON)transansactions的行爲 - more here

1

開箱即用,如果你使用SSIS來做到這一點,你可以發送失敗的行到一個不同的路徑,或只是把它們扔出去。

1

您可能正在考慮唯一索引的IGNORE_DUP_KEY屬性。

請參閱IGNORE_DUP_KEY上的this related SO questionthe official MSDN article

您必須使用ALTER INDEX添加此屬性,或者(如果唯一約束位於主鍵上),請刪除並重新創建它。

一旦這個到位,任何插入只應拒絕無效行而不是整個批次。

+0

有沒有辦法在插入後得到失敗的行? – 2010-10-27 13:49:40

+0

我們決定不使用這個解決方案,因爲它會影響非聚簇索引的性能。我們確實利用它來分配預先定義的優惠券代碼。謝謝... – 2010-10-27 14:57:55