2010-12-03 29 views
7

L'instruction SQL suivante ci-dessous est un bon exemple de code SQL qui génère une exception avec des détails imbriqués. Il semble dans la partie catch de la déclaration que je ne peux obtenir des détails d'exception extérieure Could not create constraint. See previous errors (pas très utile!). Ce que je veux est le message d'exception interne:Incident de message d'exception interne SQL Server try-catch

Présentation de contrainte FOREIGN KEY 'FK_TWO' sur la table 'TABLEAU2' peut provoquer cycles ou plusieurs chemins en cascade. Indiquez ON DELETE NO ACTION ou ON ACTUALISER SANS ACTION ou modifiez d'autres contraintes FOREIGN KEY (vous pouvez obtenir ce message en exécutant le code sans try-catch).

Dans le bloc Catch, comment cela peut-il être réalisé en T-SQL?

BEGIN TRY 
     BEGIN TRAN; 

     CREATE TABLE TABLE1 (USER_ID INTEGER NOT NULL PRIMARY KEY, USER_NAME 
      CHAR(50) NOT NULL); 

     CREATE TABLE TABLE2 (AUTHOR_ID INTEGER NOT NULL PRIMARY KEY, AUTHOR_NAME 
      CHAR(50) NOT NULL, LASTMODIFIEDBY INTEGER NOT NULL, ADDEDBY INTEGER NOT 
      NULL); 

     ALTER TABLE TABLE2 ADD CONSTRAINT FK_ONE FOREIGN KEY (LASTMODIFIEDBY) 
      REFERENCES TABLE1 (USER_ID) ON DELETE CASCADE ON UPDATE CASCADE; 

     ALTER TABLE TABLE2 ADD CONSTRAINT FK_TWO FOREIGN KEY (ADDEDBY) 
      REFERENCES TABLE1(USER_ID) ON DELETE NO ACTION ON UPDATE CASCADE; 

     COMMIT TRAN; 
END TRY 
BEGIN CATCH 

     DECLARE @ERROR_MSG NVARCHAR(MAX), @SEVERITY INT, @STATE INT 
     SELECT @SEVERITY = ERROR_SEVERITY(), @STATE = ERROR_STATE() 
      , @ERROR_MSG = ERROR_MESSAGE() + ' err src line: ' + CAST(ERROR_LINE() AS NVARCHAR(20)) + ' ' + ISNULL(ERROR_PROCEDURE(), ''); 

     ROLLBACK; 
     -- RE-THROW EXCEPTION FOR DIAGNOSTIC VISIBILITY 
     RAISERROR (@ERROR_MSG ,@SEVERITY, @STATE); 
END CATCH; 

[Modifier]

Il semble donc après beaucoup de recherches qu'il n'y a pas de solution à ce problème. J'espère qu'ils vont corriger cela dans une version future.

+1

Je ne pense pas qu'il existe un moyen de le faire. Voir aussi cette question connexe: [Capture de plusieurs messages d'erreur à partir d'une seule instruction] (http://stackoverflow.com/questions/3697492/capturing-multiple-error-messages-from-a-single-statement) –

Répondre

0

Il n'y a pas de solution à ce problème maintenant. Selon this la solution dans la prochaine version de SQL Server sera d'utiliser le nouveau mot clé throw qui relancera les deux erreurs.

+0

[Il peut y avoir une solution si vous êtes prêt à désordonner sur l'analyse du tampon de sortie pour le faire fonctionner!] (http://stackoverflow.com/questions/3697492/capturing-multiple-error-messages-from-a-single-statement/5773071 # 5773071) –

9

Vous ne pouvez pas relancer l'erreur d'origine. Vous devez lancer une nouvelle erreur , avec un numéro d'erreur supérieur à 50000, qui contient le message d'erreur capturé. Voir Exception handling and nested transactions pour un exemple:

begin catch 
    declare @error int, @message varchar(4000), @xstate int; 
    select @error = ERROR_NUMBER() 
     , @message = ERROR_MESSAGE(); 
raiserror ('Caught exception: %d: %s', 16, 1, @error, @message) ; 
return; 
end catch 

L'article I a un exemple lié plus approfondi, couvrant également la vérification XACT_STATE() obligatoire et le mélange des blocs try/catch avec la sémantique de transaction.

Avec la prochaine version ("Denali") ce problème est résolu, car vous avez la possibilité d'émettre un throw; sans aucun argument, ce qui soulèvera l'exception d'origine comme dans d'autres langages try/catch. Voir TRY CATCH THROW: Error handling changes in T-SQL

Mise à jour

D'oh, je sorte de lire le poste en diagonale. Si d'autres exceptions sont soulevées, vous ne pouvez en attraper qu'une seule. C'est toujours vrai, avec Denali aussi. Mais la plupart du temps, les exceptions soulevées sont la gravité 0 (ce qui signifie qu'ils sont vraiment des impressions, pas des exceptions) et ceux-ci le font encore au client sous forme de messages d'information (SqlConnection.InfoMessage événements).