Comment faire pour que sqlcmd retourne un ERRORLEVEL différent de 0 lorsque le script .sql échoue?

38

J'exécute sqlcmd à partir d'un fichier de commandes et je me demandais comment lui faire renvoyer un ERRORLEVEL autre que 0 en cas de problème avec la sauvegarde.

leeand00
la source
Avez-vous envisagé d'utiliser quelque chose de plus robuste (en particulier pour la gestion des erreurs) que les fichiers de commandes?
Aaron Bertrand
Oh, tu veux dire comme Powershell? Nous y allions avec la méthode recommandée par la société pour le produit que nous utilisons. Problème est la méthode recommandée suppose que vous sauvegardez une base de données; mais j'ai surmonté cet obstacle. Donc, il n'y a aucun moyen de le faire simplement jeter un code d'erreur si la sauvegarde ne fonctionne pas?
leeand00
3
Pour ce que cela vaut, dans mon travail actuel, nous utilisons les procédures stockées de sauvegarde d'Ola Hallengren (avec certaines procédures stockées d'encapsuleurs internes) pour sauvegarder des milliers de bases de données sur des centaines de serveurs, et nous n'avons rencontré aucun problème avec celles-ci.
James L

Réponses:

54

Vous devez utiliser l'option -b dans sqlcmd.

-b Spécifie que sqlcmd se ferme et renvoie une valeur DOS ERRORLEVEL lorsqu'une erreur se produit. La valeur renvoyée à la variable DOS ERRORLEVEL est 1 lorsque le message d'erreur SQL Server a un niveau de gravité supérieur à 10; sinon, la valeur renvoyée est 0

http://msdn.microsoft.com/en-us/library/ms162773.aspx

Ola Hallengren
la source
10

De la page Utilitaire MSDN SQLCMD à l’ adresse : http://msdn.microsoft.com/en-us/library/ms162773.aspx

Si RAISERROR est utilisé dans un script sqlcmd et qu'un état de 127 est déclenché, sqlcmd se ferme et renvoie l'ID du message au client. Par exemple:

RAISERROR (50001, 10, 127)

Vous pouvez donc envelopper la BACKUP DATABASE...commande dans un TRY...CATCHbloc et générer le message d'erreur approprié, qui sqlcmdsera ensuite renvoyé dans votre fichier de commandes.

Par exemple, considérons le errorleveltest.sqlfichier suivant :

:ON ERROR EXIT
BEGIN TRY
    /* creates error 3147 Backup and restore operations 
            are not allowed on database tempdb */
    BACKUP DATABASE tempdb; 
END TRY
BEGIN CATCH
    DECLARE @msg NVARCHAR(255);
    SET @msg = 'An error occurred: ' + ERROR_MESSAGE();
    RAISERROR (50002, 10, 127);
END CATCH

Et le fichier .bat suivant: (la première ligne est encapsulée pour des raisons de lisibilité, mais doit figurer sur une seule ligne.)

@echo off
"C:\Program Files\Microsoft SQL Server\110\Tools\Binn\sqlcmd" -S "someinstance" -E 
    -i .\errorleveltest.sql
ECHO Errorlevel: %ERRORLEVEL%

Cela retourne ce qui suit à partir de mon invite cmd.exe:

Msg 18054, Level 16, State 1, Server CP708-D377\MV, Line 9
Error 50002, severity 10, state 127 was raised, but no message with that error number 
was found in sys.messages. If error is larger than 50000, make sure the user-defined 
message is added using sp_addmessage.
Errorlevel: 1

Comme vous pouvez le constater, ERRORLEVEL 1 est renvoyé au lieu de la valeur de retour normale de 0. Je ne parviens pas à obtenir que ERRORLEVEL reflète le numéro d'erreur actuel, dans ce cas 50002; peut-être il y a un problème dans mon code, ou peut-être il y a un problème avec mon environnement.

Max Vernon
la source
1
J'ai constaté que cela ne fonctionne que si vous fournissez une valeur numérique en tant que premier paramètre de RAISERROR. Par exemple, ceci renvoie% errorlevel% = 1: RAISERROR (50002, 10,127), mais renvoie% errorlevel% = 0: RAISERROR ('myErrMsg.', 10,127)
5
FYI concernant le dernier paragraphe: ERRORLEVELne devrait pas avoir la même valeur que le numéro d’erreur rapporté par SQL Server. ErrorNumber est une valeur spécifique à SQL Server indiquant la raison pour laquelle elle (SQL Server) s'est terminée. D'autre part, ERRORLEVELune valeur spécifique à SQLCMD indique pourquoi elle (c'est-à-dire SQLCMD) s'est terminée.
Solomon Rutzky