Cara memecahkan eksekusi skrip SQL

16

Saya sedang mengerjakan skrip sql dan saya memiliki persyaratan untuk berhenti melanjutkan skrip jika beberapa kondisi tidak terpenuhi.

Ketika saya Google itu, saya menemukan RaisError dengan 20 tingkat keparahan akan menghentikannya. Tetapi untuk beberapa alasan saya tidak dapat menggunakan opsi itu.

Tolong beri saya alternatif apa yang memungkinkan untuk menghentikan eksekusi skrip SQL.

Pengembang Baru
sumber
1
Mengapa memunculkan kesalahan tidak dapat diterima? Apakah skrip ini prosedur tersimpan?
Namphibian
Saya tidak mengerti pertanyaan tinju Anda dengan jelas. Untuk pertanyaan kedua; tidak, ini bukan SP
Pengembang Baru
1
Apa skripnya? Apakah ini terdiri dari beberapa batch? Sudahkah Anda melihat jawabannya di sini?
Martin Smith

Jawaban:

8

Dari dokumentasi RAISERROR (penekanan saya):

Tingkat keparahan dari 0 hingga 18 dapat ditentukan oleh pengguna mana pun. Tingkat keparahan dari 19 hingga 25 hanya dapat ditentukan oleh anggota peran server tetap sysadmin atau pengguna dengan izin ALTER TRACE. Untuk tingkat keparahan dari 19 hingga 25, opsi DENGAN LOG diperlukan.

Kemungkinan besar kepala sekolah Anda menjalankan skrip karena tidak memenuhi kriteria ini.

Tidak ada yang salah dengan menggunakan RAISERROR; Anda hanya menggunakan tingkat keparahan yang berlebihan. Saya menggunakan level 16 sebagai default untuk kesalahan yang muncul dan urutannya akan diakhiri. Jika Anda ingin lebih akurat, Anda dapat mengikuti level yang diberikan oleh Microsoft sendiri:

masukkan deskripsi gambar di sini

Sekarang, setelah mengatakan semua itu, tergantung pada konteks skripnya, gunakan RAISERROR mungkin tidak cukup, karena tidak "keluar" dari skrip dengan sendirinya (menggunakan tingkat keparahan normal).

Sebagai contoh:

RAISERROR(N'Test', 16, 1);

SELECT 1;   /* Executed! */

Ini akan baik meningkatkan kesalahan dan mengembalikan hasil set.

Untuk segera menghentikan skrip, saya lebih suka menggunakan RETURN(menggunakan GOTOkonstruksi -type umumnya tidak disarankan di sebagian besar lingkaran pemrograman di mana alternatif ada):

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */

Atau atasi penggunaan kesalahan TRY/CATCH, yang akan menyebabkan eksekusi melompat ke CATCHblok jika keparahannya 11 atau lebih tinggi:

BEGIN TRY
    RAISERROR(N'Test', 16, 1);
    SELECT 1;   /* Not executed */
END TRY
BEGIN CATCH
    SELECT 2;   /* Executed */
END CATCH

BEGIN TRY
    RAISERROR(N'Test', 10, 1);
    SELECT 1;   /* Executed */
END TRY
BEGIN CATCH
    SELECT 2;   /* Not executed */
END CATCH

Masalah terpisah adalah jika skrip membentang beberapa batch - RETURNhanya akan keluar dari batch :

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

Untuk memperbaiki ini, Anda dapat memeriksa @@ERROR di awal setiap batch:

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
    RETURN;

SELECT 2;   /* Not executed */

Sunting: Seperti yang ditunjukkan Martin Smith dengan benar dalam komentar, ini hanya berfungsi untuk 2 kumpulan. Untuk memperluas ke 3 atau lebih batch, Anda dapat melakukan kesalahan peningkatan kaskade seperti itu (catatan: GOTOmetode ini tidak menyelesaikan masalah ini karena label target harus didefinisikan dalam batch):

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
BEGIN
    RAISERROR(N'Error already raised. See previous errors.', 16, 1);
    RETURN;
END

SELECT 2;   /* Not executed */
GO

IF (@@ERROR != 0)
BEGIN
    RAISERROR(N'Error already raised. See previous errors.', 16, 1);
    RETURN;
END

SELECT 3;   /* Not executed */

Atau, seperti yang dia tunjukkan, Anda dapat menggunakan SQLCMDmetode ini jika itu sesuai untuk lingkungan Anda.

Jon Seigel
sumber
Saran terakhir itu tidak berhasil. Lihat pastebin . Saya suka metode sqlcmd di sini
Martin Smith
6

Anda dapat menggunakan GOTOpernyataan untuk melompat-lompat di mana pun Anda inginkan. Dengan kata lain, Anda mengalami kesalahan atau kondisi lain, dan Anda dapat memiliki label di bagian bawah skrip (yaitu TheEndOfTheScript:) dan hanya mengeluarkan goto TheEndOfTheScript;pernyataan.

Berikut ini adalah contoh cepat:

print 'here is the first statement...';

print 'here is the second statement...';

-- substitute whatever conditional flow determining factor
-- you'd like here. I have chosen a dummy statement that will
-- always return true
--
if (1 = 1)
    goto TheEndOfTheScript;

print 'here is the third statement...';

print 'here is the fourth statement...';


TheEndOfTheScript:
print 'here is the end of the script...';

Output dari eksekusi ini adalah sebagai berikut:

here is the first statement...
here is the second statement...
here is the end of the script...

Seperti yang Anda lihat, GOTOtelah melewatkan mencetak pernyataan ketiga dan keempat dan langsung melompat ke label ( TheEndOfTheScript).

Thomas Stringer
sumber
7
Hanya berfungsi ketika ada satu batch, akan pecah segera setelah Anda memiliki pernyataan GO.
Gabriel
0

Setuju dengan SET NOEXEC ON/OFF, namun dalam Stored Procs (mengandung satu blok) saya cukup menggunakan RETURNpernyataan.

Peringatan: Dalam file skrip, jika Anda memiliki beberapa GOpernyataan, RETURNhanya akan keluar dari blok saat ini dan melanjutkan dengan blok / batch berikutnya.

Catatan: GOTOseharusnya merupakan praktik pengkodean yang buruk, TRY..CATCHdirekomendasikan penggunaan " ", seperti yang diperkenalkan sejak SQL Server 2008, diikuti THROWpada tahun 2012.

Eddie Kumar
sumber