Jak sprawić, aby sqlcmd zwrócił ERRORLEVEL inny niż 0, gdy skrypt .sql zawiedzie?


38

Korzystam z narzędzia sqlcmd z pliku wsadowego i zastanawiałem się, jak sprawić, by zwrócił błąd ERRORLEVEL inny niż 0, gdy coś pójdzie nie tak z kopią zapasową.


Czy rozważałeś użycie czegoś bardziej niezawodnego (szczególnie przy obsłudze błędów) niż pliki wsadowe?
— Aaron Bertrand

Och, masz na myśli Powershell? Właśnie stosowaliśmy zalecaną przez firmę metodę dla produktu, którego używamy. Problem jest zalecaną metodą zakładającą, że tworzysz kopię zapasową jednej bazy danych; ale pokonałem tę przeszkodę. Więc nie ma sposobu, aby rzucić kod błędu, jeśli kopia zapasowa nie działa?
— leeand00

3
Za to, co jest warte, w mojej obecnej pracy korzystamy z zapasowych procedur przechowywanych Oli Hallengren (z kilkoma wewnętrznymi procedurami przechowywanymi wokół nich) do tworzenia kopii zapasowych tysięcy baz danych na setkach serwerów i nie mieliśmy z nimi problemów.
— James L

Odpowiedzi:


54

Powinieneś użyć opcji -b w sqlcmd.

-b Określa, że ​​sqlcmd kończy działanie i zwraca wartość DOS ERRORLEVEL, gdy wystąpi błąd. Wartość zwracana do zmiennej DOS ERRORLEVEL wynosi 1, gdy komunikat o błędzie programu SQL Server ma poziom ważności większy niż 10; w przeciwnym razie zwracana jest wartość 0

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


10

Ze strony narzędzia MSDN SQLCMD pod adresem : http://msdn.microsoft.com/en-us/library/ms162773.aspx

Jeśli RAISERROR zostanie użyty w skrypcie sqlcmd, a stan 127 zostanie podniesiony, sqlcmd zakończy pracę i zwróci identyfikator komunikatu z powrotem do klienta. Na przykład:

RAISERROR (50001, 10, 127)

Możesz więc zawinąć BACKUP DATABASE...polecenie w TRY...CATCHblok i wywołać odpowiedni komunikat o błędzie, który sqlcmdnastępnie powróci do pliku wsadowego.

Na przykład rozważ następujący errorleveltest.sqlplik:

: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

I następujący plik .bat: (pierwszy wiersz jest zawijany dla czytelności, ale musi znajdować się w jednym wierszu).

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

Zwraca to następujące polecenie z wiersza polecenia 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

Jak widać, zwracany jest ERRORLEVEL 1 zamiast normalnej wartości 0. Nie mogę uzyskać ERRORLEVEL odzwierciedlającej faktyczny numer błędu, w tym przypadku 50002; być może jest jakiś problem w moim kodzie, a może jest jakiś problem z moim środowiskiem.


1
Przekonałem się, że działa to TYLKO, jeśli podasz wartość liczbową jako pierwszy parametr RAISERROR. na przykład: Zwraca% poziom błędu% = 1: RAISERROR (50002, 10,127) Ale zwraca%% poziom błędu% = 0: RAISERROR ('myErrMsg., 10,127)

5
Informacje dotyczące ostatniego akapitu: ERRORLEVELnie należy oczekiwać, że będą miały tę samą wartość, co numer błędu zgłoszony z SQL Server. ErrorNumber jest wartością specyficzną dla SQL Server, która wskazuje, dlaczego (tj. SQL Server) została zakończona. Z drugiej strony ERRORLEVELjest wartością specyficzną dla SQLCMD, która wskazuje, dlaczego (tj. SQLCMD) została zakończona.
— Solomon Rutzky,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.