2010-10-26 34 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