¿Cómo hacer que sqlcmd devuelva un ERRORLEVEL distinto de 0 cuando falla el script .sql?


38

Estoy ejecutando sqlcmd desde un archivo por lotes y me preguntaba cómo hacer que devuelva un ERRORLEVEL que no sea 0 cuando algo sale mal con la copia de seguridad.


¿Ha considerado usar algo más robusto (particularmente en el manejo de errores) que los archivos por lotes?
Aaron Bertrand

¿Te refieres a Powershell? Solo íbamos con el método recomendado por la compañía para el producto que estamos usando. El problema es que el método recomendado supone que está haciendo una copia de seguridad de una base de datos; Pero he superado ese obstáculo. Entonces, ¿no hay forma de que solo arroje un código de error si la copia de seguridad no funciona?
leeand00

3
Para lo que vale, en mi trabajo actual, utilizamos los procedimientos almacenados de copia de seguridad de Ola Hallengren (con algunos procedimientos almacenados de envoltorio internos a su alrededor) para respaldar miles de bases de datos en cientos de servidores, y no hemos tenido problemas con ellos.
James L

Respuestas:


54

Debe usar la opción -b en sqlcmd.

-b Especifica que sqlcmd sale y devuelve un valor de ERRORLEVEL de DOS cuando se produce un error. El valor que se devuelve a la variable ERRORLEVEL de DOS es 1 cuando el mensaje de error de SQL Server tiene un nivel de gravedad mayor que 10; de lo contrario, el valor devuelto es 0

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


10

Desde la página de MSDN SQLCMD Utility en: http://msdn.microsoft.com/en-us/library/ms162773.aspx

Si se utiliza RAISERROR dentro de un script sqlcmd y se genera un estado de 127, sqlcmd se cerrará y devolverá la ID del mensaje al cliente. Por ejemplo:

RAISERROR (50001, 10, 127)

Entonces, podría envolver el BACKUP DATABASE...comando en un TRY...CATCHbloque y generar el mensaje de error apropiado, que sqlcmdluego volvería a su archivo por lotes.

Por ejemplo, considere el siguiente errorleveltest.sqlarchivo:

: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

Y el siguiente archivo .bat: (la primera línea está ajustada para facilitar la lectura, pero debe estar en una sola línea).

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

Esto devuelve lo siguiente desde mi indicador 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

Como puede ver, ERRORLEVEL 1 se devuelve en lugar del valor de retorno normal de 0. No puedo hacer que ERRORLEVEL refleje el número de error real, en este caso 50002; quizás haya un problema en mi código, o quizás haya algún problema con mi entorno.


1
Descubrí que esto SOLO funciona si proporciona un valor numérico como primer parámetro de RAISERROR. por ejemplo: Esto devuelve un% errorlevel% = 1: RAISERROR (50002, 10,127) Pero esto devuelve% errorlevel% = 0: RAISERROR ('myErrMsg.', 10,127)

55
Para su información con respecto al último párrafo: ERRORLEVELno se debe esperar que sea el mismo valor que el Número de error informado desde SQL Server. ErrorNumber es un valor específico de SQL Server para indicar por qué terminó (es decir, SQL Server). Por otro lado, ERRORLEVELes un valor específico de SQLCMD para indicar por qué terminó (es decir, SQLCMD).
Solomon Rutzky
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.