2010-10-26 9 views
2

Je voudrais faire une insertion en utilisant un select, mais je sais que certaines lignes peuvent échouer (ce qui est attendu). Existe-t-il un moyen de désactiver les transactions implicites de SQL Server 2008 afin que celles qui n'ont pas échoué ne soient pas annulées?Désactiver les transactions implicites

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

Répondre

2

non, l'instruction INSERT est une commande unique. Les transactions contrôlent la façon dont plusieurs commandes sont combinées en une seule unité de travail, et non comment les lignes sont combinées au sein d'une seule commande. Vous ne pouvez pas avoir des lignes INSERT et celles qui échouent (problème de contrainte) et être simplement ignorées. Si des lignes échouent, l'INSERT entier échoue. Pourquoi ne pas essayer de modifier le SELECT pour exclure les lignes qui échoueront?

quelque chose comme:

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

Je génère un code coupon aléatoire pour chaque ligne et il y a une contrainte unique sur le code coupon. Au lieu de faire une sélection pour voir si elle existe, je laisse SQL Server gérer la contrainte et laisser échouer. Pensez-vous que la vérification du compte (*) avec ce code promo sera plus rapide? –

+0

êtes-vous en boucle, avec un insert par itération? si c'est le cas, affichez le code afin que je puisse voir exactement ce qui se passe. Il existe des moyens de générer un ensemble de nombres aléatoires: http://stackoverflow.com/questions/183124/multiple-random-values-in-sql-server-2005/183183#183183. Aussi COUNT (*) est lent (il fait plus de travail) que juste un EXISTS uni. –

+0

oui, je suis en boucle. J'ai ajouté le code. Bottom line J'ai besoin de rendre cette requête aussi efficace que possible. Peut-être qu'au lieu d'obtenir le compte à chaque itération, exécutez le select top 1 et faites WHILE NOT @customerid est nul. D'autres suggestions? –

0

Il est possible de contrôler le comportement de transansactions en utilisant SET XACT_ABORT OFF (ON) - more here.

1

Si vous utilisez SSIS pour cela, vous pouvez envoyer vos lignes échouées sur un chemin différent ou simplement les jeter.

1

Vous pensez probablement à la propriété IGNORE_DUP_KEY d'un index unique.

Voir this related SO question et the official MSDN article sur IGNORE_DUP_KEY.

Vous devez utiliser ALTER INDEX pour ajouter cette propriété ou, si la contrainte unique est sur la clé primaire, la supprimer et la recréer. Une fois que cela est en place, les insertions doivent uniquement rejeter les lignes non valides au lieu du lot entier.

+0

est-il un moyen d'obtenir les lignes qui ont échoué après l'insertion? –

+0

Nous avons décidé de ne pas utiliser cette solution car elle affecte les performances des index non clusterisés. Nous l'avons utilisé pour allouer des codes promo prédéfinis. Merci... –