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

no, 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

Я генерирую случайный код купона для каждой строки, и существует уникальное ограничение на код купона. Вместо того, чтобы делать выбор, чтобы увидеть, существует ли он, я позволяю SQL Server обрабатывать ограничение и препятствовать ему. Считаете ли вы, что проверка количества (*) с этим кодом купона будет быстрее? –

+0

вы зацикливаетесь, с одной вставкой на итерацию? если это так, отправьте код, чтобы я мог точно видеть, что происходит. существуют способы генерации набора случайных чисел: http://stackoverflow.com/questions/183124/multiple-random-values-in-sql-server-2005/183183#183183. Также COUNT (*) работает медленно (это работает больше), чем обычный EXISTS. –

+0

да, я петлю. Я добавил код. В заключение я должен сделать этот запрос максимально эффективным. Возможно, вместо того, чтобы подсчитывать на каждой итерации, просто выполните select top 1 и сделайте WHILE NOT @customerid равным null. Любые другие предложения? –

0

можно управлять поведением transansactions с помощью SET XACT_ABORT OFF (ON) - more here.

1

Мышление из коробки, если вы используете SSIS для этого, вы можете отправить свои поврежденные строки по другому пути или просто выбросить их.

1

Возможно, вы, вероятно, думаете о свойстве IGNORE_DUP_KEY уникального индекса.

См. this related SO question и the official MSDN article по адресу IGNORE_DUP_KEY.

Чтобы добавить это свойство, вам нужно либо использовать ALTER INDEX, либо (если уникальное ограничение находится на первичном ключе) отбросить и воссоздать его.

Как только это на месте, любые вставки должны только отклонять недопустимые строки вместо всей партии.

+0

Есть ли способ получить строки, которые не удалось после вставки? –

+0

мы решили не идти с этим решением, потому что оно влияет на производительность некластеризованных индексов. Мы использовали его для распределения предопределенных кодов купонов. Благодаря... –

Смежные вопросы