web-dev-qa-db-fra.com

Que signifient les différents niveaux de gravité RAISERROR?

Mon meilleur résultat Google a été this :

  • ci-dessous 11 sont des avertissements, pas des erreurs
  • 11-16 sont disponibles pour utilisation
  • au-dessus de 16 sont des erreurs système
  • il n'y a pas de différence de comportement entre 11-16

Mais, à partir de BOL, "les niveaux de gravité de 0 à 18 peuvent être spécifiés par n'importe quel utilisateur."

Dans ma procédure stockée particulière, je veux que l'erreur soit renvoyée à une application cliente .Net, donc il semble que n'importe quel niveau de gravité entre 11 et 18 ferait l'affaire. Quelqu'un possède-t-il des informations faisant autorité sur la signification de chacun des niveaux et sur la manière dont ils devraient être utilisés?

69
Steve S.

Niveaux de gravité du moteur de base de données

Vous devez renvoyer 16. Est le niveau d'erreur par défaut le plus utilisé:

Indique des erreurs générales pouvant être corrigées par l'utilisateur.

Ne retournez pas 17-18, ceux-ci indiquent des erreurs plus graves, comme des problèmes de ressources:

Indiquez les erreurs logicielles qui ne peuvent pas être corrigées par l'utilisateur. Informez votre administrateur système du problème.

Ne retournez pas non plus 11-15 car ceux-ci ont une signification particulière attachée à chaque niveau (14 - accès de sécurité, 15 - erreur de syntaxe, 13 - blocage etc.).

Le niveau 16 ne met pas fin à l'exécution.

Lorsque votre intention est de consigner un avertissement mais de poursuivre l'exécution, utilisez plutôt un niveau de gravité inférieur à 10.

101
Remus Rusanu

Niveau de gravité 16 can Terminer l'exécution.

AVIS TRY-CATCH avec RAISERROR ():

RAISERROR() avec une gravité de 16 termine l'exécution de tout ce qui se trouve en dessous de la ligne incriminée.
( Cependant ceci seulement s'applique à l'intérieur d'un Try-Block.

--DECLARE @DivideByZero Int = 1/0--Uncommenting this will Skip everything below.
RAISERROR (N'Before Try: Raise-Error 16.', 16, 0)--Works.
SELECT 'Before Try: Select.'[Marker]--Works.
BEGIN TRY
    RAISERROR (N'Inside Try: Raise-Error 16.', 16, 0)--Not displayed,but sends to Catch-Block.
    SELECT 'Inside Try: Select.'[Marker]--Skipped.
END TRY
BEGIN CATCH
    RAISERROR (N'Inside Catch: Raise-Error 16.', 16, 0)--Works.
    SELECT 'Inside Catch: Select.'[Marker]--Works.
    --RETURN --Adding Return will only skip what is After the Catch-Block for this scope only.
    --;THROW--Shows the RAISERROR() from the Try-Block and Halts Execution. Must include ";".
END CATCH
RAISERROR (N'After Try-Catch: Raise-Error 16.', 16, 0)--Works.
SELECT 'After Try-Catch: Select.'[Marker]--Works.

Surpris? Donc étais-je.
Ce qui m'a aussi jeté pour une boucle n'est pas tous les niveaux de gravité -16 sont les mêmes.
Si vous deviez décommenter la ligne Divide-By-Zero tout en haut, alors rien en dessous ne fonctionnerait.
La logique Divide-By-Zero générera également une exception de gravité -16,
mais il est géré avec un point final, contrairement à une projection avec RAISERROR().

Remarque: Utilisez ;THROW Comme dernière ligne à l'intérieur de votre bloc de capture faire correctement
Lève l'exception SQL pour l'événement RAISERROR() déclenché par votre Try-Block.
Cela arrêtera effectivement l'exécution avec un point final.
Le point-virgule ; Est requis lorsque d'autres lignes existent dans le Catch-Block avant d'appeler ;THROW.
Si votre logique gère correctement l'erreur dans le bloc de capture (et que vous souhaitez continuer le traitement
Le reste de la logique après), puis ne pas utiliser ;THROW.

Conclusion:

Ne confondez pas une gravité -16 lancée par le moteur SQL-Server
Avec celui que vous vous élevez en utilisant RAISERROR().
À toutes fins utiles (lorsque vous lancez délibérément vos propres erreurs), ne considérez que 2 gravités:
(pour information ou avertissement) et
16 (pour lancer une exception gérée dans un Try-Block - pour la renvoyer au Catch-Block).

Information maintenant!

Remarque: Si vous utilisez RAISERROR() pour afficher les messages d'information,
Puis je suggère d'utiliser WITH NOWAIT:

RAISERROR('Read me right now!', 0, 1) WITH NOWAIT
RAISERROR('Read me whenever.' , 0, 1)
DECLARE @WaitSeconds Int = 10
DECLARE @WaitFor DateTime = DATEADD(SECOND, @WaitSeconds, 0)
WAITFOR DELAY @WaitFor

Ceci est particulièrement utile lors de longues opérations par lots lorsque vous souhaitez obtenir des informations
Sur la façon dont les choses progressent lorsque vous atteignez certains marqueurs de jalons tout au long du lot.
En pas en utilisant WITH NOWAIT, Vous ne saurez peut-être jamais quand vos messages d'information peuvent apparaître.
Ils peuvent apparaître par intermittence tout au long du lot, ou d'un coup lorsque le lot est terminé.

5
MikeTeeVee