2013-02-21 1 views
43

Dans ma procédure stockée, j'ai trois instructions d'insertion.Comment faire pour annuler ou valider une transaction dans SQL Server

Lors de l'insertion en double valeur de clé deux premières requêtes génèrent l'erreur

Violation de contrainte PRIMARY KEY

et la troisième requête fonctionne comme d'habitude.

Maintenant, je veux que si une requête génère une exception, tout devrait être annulé.

S'il n'y a aucune exception générée par une requête, elle devrait être validée.

declare @QuantitySelected as char 
    set @QuantitySelected = 2 

    declare @sqlHeader as varchar(1000) 
    declare @sqlTotals as varchar(1000) 
    declare @sqlLine as varchar(1000) 

    select @sqlHeader = 'Insert into tblKP_EstimateHeader ' 
    select @sqlHeader = @sqlHeader + '(CompanyID,CompanyName,ProjectName,EstimateID,EstimateHeader,QuoteDate,ValidUntil,RFQNum,Revision,Contact,Status,NumConfigurations) ' 
    select @sqlHeader = @sqlHeader + ' select CompanyID,CompanyName,ProjectName,EstimateID,EstimateHeader,QuoteDate,ValidUntil,RFQNum,Revision,Contact,Status,NumConfigurations ' 
    select @sqlHeader = @sqlHeader + 'from V_EW_Estimate_Header where EstimateID = 2203' 



    select @sqlTotals = 'Insert into tblKP_Estimate_Configuration_Totals ' 
    select @sqlTotals = @sqlTotals + '(ConfigRecId,RecId,SellQty,ConfigNum,ConfigDesc,SortOrder,OptionsInMainPrice,MarkupPctQty,' 
    select @sqlTotals = @sqlTotals + ' SellPriceQty,RubberStamp,OptPriceQty,StatusRecid,LastUpdate_Date,LastUpdate_User,TotalCost,QuantityBracketSelected)' 
    select @sqlTotals = @sqlTotals + ' select ConfigRecId,RecId,SellQty' + @QuantitySelected + ',ConfigNum,ConfigDesc,SortOrder,OptionsInMainPrice' 
    select @sqlTotals = @sqlTotals + ' ,MarkupPctQty' + @QuantitySelected + ',SellPriceQty' + @QuantitySelected + ',RubberStamp,OptPriceQty' + @QuantitySelected + ',StatusRecid,LastUpdate_Date,LastUpdate_User,TotalCost' + @QuantitySelected + ',' + @QuantitySelected 
    select @sqlTotals = @sqlTotals + ' from v_EW_Estimate_Configuration_Totals where ConfigRecId = -3' 


    select @sqlLine = 'Insert into tblKP_Estimate_Configuration_Lines' 
    select @sqlLine = @sqlLine + '(MstrRfqRecId,RfqRecId,RfqLineRecId,CompanyId,VendorQuoteNum,LineGrp,LineNum,StatusRecId,' 
    select @sqlLine = @sqlLine + ' LineDesc,LineSize,LineMatl,LineDeco,LineFinish,CopyFromRecId,PerPieceCost,IsOptional,' 
    select @sqlLine = @sqlLine + ' CopyToNewRev,RecId,UnitPrice,LineQty,LinePrice,CustOrVend,SellQty1,RfqNum,ConfigLineIsOptional,ConfigLinePerPieceCost,ConfigLineRecid,SellPrice,SaleQty)' 
    select @sqlLine = @sqlLine + ' select distinct MstrRfqRecId,RfqRecId,RfqLineRecId,CompanyId,VendorQuoteNum,LineGrp,LineNum,' 
    select @sqlLine = @sqlLine + ' StatusRecId,LineDesc,LineSize,LineMatl,LineDeco,LineFinish,CopyFromRecId,PerPieceCost,IsOptional,' 
    select @sqlLine = @sqlLine + ' CopyToNewRev,RecId,UnitPrice' + @QuantitySelected + ',LineQty' + @QuantitySelected + ', isnull(LinePrice' + @QuantitySelected + ', 0.0000),CustOrVend,SellQty' + @QuantitySelected + ',RfqNum,ConfigLineIsOptional,ConfigLinePerPieceCost,ConfigLineRecid,SellPrice' + @QuantitySelected + ',SaleQty' + @QuantitySelected 
    select @sqlLine = @sqlLine + ' from v_EW_EstimateLine where rfqlinerecid in (select RfqLineRecID from kp_tblVendorRfqConfigLine where ConfigRecID = -3) ' 

    exec(@sqlHeader) 
    exec(@sqlTotals) 
    exec(@sqlLine) 
+0

Bienvenue dans StackOverflow: si vous postez du code, des échantillons XML ou des données, ** veuillez ** mettre en surbrillance ces lignes dans l'éditeur de texte et cliquer sur le bouton "code samples" dans la barre d'outils de l'éditeur. le format et la syntaxe le mettent en évidence! –

+0

@marc_s merci marc. J'ai ajouté mon StoreProcedure. Vérifie s'il te plaît. –

+0

C'est une ** procédure stockée ** - une ** procédure ** qui est ** stockée ** dans SQL Server - elle n'a rien à voir avec un "magasin" .... –

Répondre

132

Les bonnes nouvelles sont une transaction dans SQL Server peut couvrir plusieurs lots (chaque exec est traité comme un lot séparé.)

Vous pouvez envelopper vos EXEC déclarations dans un BEGIN TRANSACTION et COMMIT mais vous besoin d'aller plus loin et revenir en arrière si des erreurs se produisent.

Idéalement, vous voudriez quelque chose comme ceci:

BEGIN TRY 
    BEGIN TRANSACTION 
     exec(@sqlHeader) 
     exec(@sqlTotals) 
     exec(@sqlLine) 
    COMMIT 
END TRY 
BEGIN CATCH 

    IF @@TRANCOUNT > 0 
     ROLLBACK 
END CATCH 

Le BEGIN TRANSACTION et COMMIT je crois que vous êtes déjà au courant. Les blocs BEGIN TRY et BEGIN CATCH sont essentiellement là pour attraper et gérer les erreurs qui se produisent. Si l'une de vos instructions EXEC déclenche une erreur, l'exécution du code passe au bloc CATCH.

Votre code de construction SQL existant doit être en dehors de la transaction (ci-dessus) car vous voulez toujours garder vos transactions aussi courtes que possible.

+1

quand j'ai exécuté la déclaration. Ça fonctionne bien. mais dans storeProcedure quand cela fonctionne la première fois. Lors de la deuxième exécution de storeP, l'exception est générée: - "Nombre de transactions après EXECUTE indique un nombre incohérent d'instructions BEGIN et COMMIT Nombre précédent = 0, nombre actuel = 1." –

+2

Désolé, cela aurait dû être «SI @@ TRANCOUNT> 0», je vais mettre à jour ma réponse. –

+0

Merci. maintenant ça fonctionne bien. –

Questions connexes