Wie kann sqlcmd dazu gebracht werden, ein anderes ERRORLEVEL als 0 zurückzugeben, wenn das .sql-Skript fehlschlägt?

38

Ich verwende sqlcmd aus einer Batch-Datei und frage mich, wie ich es dazu bringen kann, ein anderes ERRORLEVEL als 0 zurückzugeben, wenn bei der Sicherung etwas schief geht.

leeand00
quelle
Haben Sie darüber nachgedacht, etwas Robusteres (insbesondere bei der Fehlerbehandlung) als Batch-Dateien zu verwenden?
Aaron Bertrand
Oh du meinst wie Powershell? Wir haben uns nur an die von der Firma empfohlene Methode für das von uns verwendete Produkt gehalten. Das Problem ist, dass die empfohlene Methode davon ausgeht, dass Sie eine Datenbank sichern. Aber ich habe diese Hürde genommen. Es gibt also keine Möglichkeit, einen Fehlercode auszulösen, wenn die Sicherung nicht funktioniert.
Dienstag,
3
Für meine derzeitige Arbeit verwenden wir Ola Hallengrens gespeicherte Sicherungsprozeduren (mit einigen internen Wrapper-gespeicherten Prozeduren), um Tausende von Datenbanken auf Hunderten von Servern zu sichern, und wir hatten keine Probleme damit.
James L

Antworten:

53

Sie sollten die Option -b in sqlcmd verwenden.

-b Gibt an, dass sqlcmd beendet wird und bei Auftreten eines Fehlers einen DOS-ERRORLEVEL-Wert zurückgibt. Der Wert, der an die DOS-Variable ERRORLEVEL zurückgegeben wird, ist 1, wenn die SQL Server-Fehlermeldung einen Schweregrad von mehr als 10 aufweist. Andernfalls lautet der zurückgegebene Wert 0

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

Ola Hallengren
quelle
9

Auf der Seite MSDN SQLCMD Utility unter: http://msdn.microsoft.com/en-us/library/ms162773.aspx

Wenn RAISERROR in einem sqlcmd-Skript verwendet wird und der Status 127 ausgelöst wird, wird sqlcmd beendet und die Nachrichten-ID an den Client zurückgegeben. Beispielsweise:

RAISERROR (50001, 10, 127)

Sie könnten den BACKUP DATABASE...Befehl also in einen TRY...CATCHBlock einschließen und die entsprechende Fehlermeldung auslösen, die sqlcmddann zu Ihrer Batch-Datei zurückkehren würde.

Betrachten Sie zum Beispiel die folgende errorleveltest.sqlDatei:

: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

Und die folgende .bat-Datei: (Die erste Zeile wird zur besseren Lesbarkeit umbrochen, muss sich jedoch in einer einzelnen Zeile befinden.)

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

Dies gibt Folgendes an meiner Eingabeaufforderung cmd.exe zurück:

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

Wie Sie sehen, wird ERRORLEVEL 1 anstelle des normalen Rückgabewerts 0 zurückgegeben. Ich kann den ERRORLEVEL nicht ermitteln, um die tatsächliche Fehlernummer wiederzugeben, in diesem Fall 50002; Möglicherweise liegt ein Problem in meinem Code vor, oder es liegt ein Problem mit meiner Umgebung vor.

Max Vernon
quelle
1
Ich habe festgestellt, dass dies NUR funktioniert, wenn Sie einen numerischen Wert als ersten Parameter von RAISERROR angeben. Beispiel: Dies gibt% errorlevel% = 1: RAISERROR (50002, 10,127) zurück. Dies gibt jedoch% errorlevel% = 0: RAISERROR ('myErrMsg.', 10,127)
5
Zu Ihrer Information bezüglich des letzten Absatzes: Es ERRORLEVELsollte nicht erwartet werden, dass der Wert mit der von SQL Server gemeldeten Fehlernummer übereinstimmt. Die Fehlernummer ist ein SQL Server-spezifischer Wert, der angibt, warum sie beendet wurde (z. B. SQL Server). Andererseits ERRORLEVELgibt ein SQLCMD-spezifischer Wert an, warum er beendet wurde (dh SQLCMD).
Solomon Rutzky,