Bagaimana membuat sqlcmd mengembalikan ERRORLEVEL selain 0 ketika skrip .sql gagal?

38

Saya menjalankan sqlcmd dari file batch dan saya bertanya-tanya bagaimana membuatnya mengembalikan ERRORLEVEL selain 0 ketika ada masalah dengan cadangan.

leeand00
sumber
Sudahkah Anda mempertimbangkan untuk menggunakan sesuatu yang lebih kuat (terutama pada penanganan kesalahan) daripada file batch?
Aaron Bertrand
Oh maksudmu seperti Powershell? Kami hanya akan menggunakan metode yang direkomendasikan perusahaan untuk produk yang kami gunakan. Masalahnya adalah metode rekomendasi menganggap Anda mencadangkan satu basis data; tapi saya sudah mengatasi rintangan itu. Jadi tidak ada cara untuk mendapatkannya hanya membuang kode kesalahan jika cadangan tidak berfungsi?
leeand00
3
Untuk apa nilainya, pada pekerjaan saya saat ini, kami menggunakan prosedur yang tersimpan cadangan Ola Hallengren (dengan beberapa prosedur tersimpan pembungkus di rumah di sekitar mereka) untuk cadangan ribuan database di ratusan server, dan kami tidak punya masalah dengan mereka.
James L

Jawaban:

54

Anda harus menggunakan opsi -b dalam sqlcmd.

-b Menentukan bahwa sqlcmd keluar dan mengembalikan nilai DOS ERRORLEVEL saat kesalahan terjadi. Nilai yang dikembalikan ke variabel DOS ERRORLEVEL adalah 1 ketika pesan kesalahan SQL Server memiliki tingkat keparahan lebih besar dari 10; jika tidak, nilai yang dikembalikan adalah 0

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

Ola Hallengren
sumber
10

Dari halaman MSDN SQLCMD Utility di: http://msdn.microsoft.com/en-us/library/ms162773.aspx

Jika RAISERROR digunakan dalam skrip sqlcmd dan status 127 dibesarkan, sqlcmd akan berhenti dan mengembalikan ID pesan kembali ke klien. Sebagai contoh:

RAISERROR (50001, 10, 127)

Jadi, Anda bisa membungkus BACKUP DATABASE...perintah di TRY...CATCHblok dan menaikkan pesan kesalahan yang sesuai, yang sqlcmdkemudian akan kembali ke file batch Anda.

Misalnya, pertimbangkan errorleveltest.sqlfile berikut :

: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

Dan file .bat berikut: (baris pertama dibungkus agar mudah dibaca, tetapi perlu satu baris.)

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

Ini mengembalikan yang berikut dari prompt cmd.exe saya:

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

Seperti yang Anda lihat, ERRORLEVEL 1 dikembalikan dan bukan nilai pengembalian normal 0. Saya tidak bisa mendapatkan ERRORLEVEL untuk mencerminkan jumlah kesalahan sebenarnya, dalam hal ini 50002; mungkin ada masalah dalam kode saya, atau mungkin ada beberapa masalah dengan lingkungan saya.

Max Vernon
sumber
1
Saya telah menemukan bahwa HANYA ini berfungsi jika Anda memberikan nilai numerik sebagai parameter pertama RAISERROR. misalnya: Ini mengembalikan% errorlevel% = 1: RAISERROR (50002, 10.127) Tetapi ini mengembalikan% errorlevel% = 0: RAISERROR ('myErrMsg.', 10.127)
5
FYI mengenai paragraf terakhir: ERRORLEVELseharusnya tidak diharapkan memiliki nilai yang sama dengan Nomor Kesalahan yang dilaporkan dari SQL Server. The ErrorNumber adalah nilai khusus SQL Server untuk menunjukkan mengapa itu (yaitu SQL Server) dihentikan. Di sisi lain, ERRORLEVELadalah nilai spesifik SQLCMD untuk menunjukkan mengapa itu (yaitu SQLCMD) dihentikan.
Solomon Rutzky