Apakah mungkin untuk memilih RAISERROR atau THROW tergantung pada versi SQL Server?

11

Ini kode saya sekarang:

BEGIN TRY
INSERT INTO TABLE (F1,F2,F3) 
VALUES ('1','2','3')
END TRY
BEGIN CATCH
;THROW
END CATCH

Bekerja dengan baik, kecuali jika dijalankan pada mesin dengan SQL 2008. Saya ingin agar blok CATCH melakukan pengecekan terhadap versi SQL dan menjalankan THROW jika itu sama atau lebih tinggi dari 2012, dan RAISERROR jika itu 2008. Saya terus berlari ke kesalahan sintaks, dan saya ingin tahu apakah itu mungkin. Bahkan sesuatu yang sederhana seperti ini tidak berfungsi untuk saya.

BEGIN CATCH
IF ((SELECT SERVERPROPERTY('productversion')) >= 11) ;THROW
END CATCH

Setiap saran sangat dihargai.

thomasjbarrett
sumber

Jawaban:

9

Tidak, ini tidak mungkin.

Ini sintaks yang tidak valid di versi sebelumnya dan akan menyebabkan kesalahan kompilasi.

Tidak mungkin untuk menyembunyikan bagian THROWdalam EXECdi dalam blok penangkap karena lemparan tanpa parameter harus langsung terkandung di dalam tangkapan.

Anda perlu menggunakan versi kode yang Anda inginkan sesuai dengan versi SQL Server yang Anda gunakan (dan sayangnya tidak ada dukungan yang baik untuk ini, baik dalam perangkat SSDT yang saya ketahui - tidak ada yang setara dengan memasukkan baris kode secara selektif melalui kompilasi bersyarat)

Martin Smith
sumber
4

Harus ditunjukkan bahwa, bahkan jika secara teknis dimungkinkan untuk bergantian antara THROWdan RAISERROR, Anda (kemungkinan besar) tidak ingin benar-benar melakukan ini. Mengapa? Karena kemampuan yang sangat bagus dari parameterless THROWuntuk melempar ulang kesalahan menggunakan Nomor Pesan yang sama (yaitu Msg 8134bukannya di Msg Xmana X> = 50000) bukan satu-satunya perbedaan di antara mereka: THROWadalah batch-dibatalkan sementara RAISERRORtidak. Ini bisa menjadi perbedaan perilaku yang penting seperti yang ditunjukkan di bawah ini.

Pengaturan Tes

--DROP PROC ##Throw;
--DROP PROC ##RaisError;

GO
CREATE PROCEDURE ##Throw
AS
SET NOCOUNT ON;
BEGIN TRY
  SELECT 1/0 AS [DivideByZero];
END TRY
BEGIN CATCH
  THROW;
END CATCH;
SELECT 1 AS [AA];
GO

CREATE PROCEDURE ##RaisError
AS
SET NOCOUNT ON;
BEGIN TRY
  SELECT 1/0 AS [DivideByZero];
END TRY
BEGIN CATCH
  RAISERROR('test, yo!', 16, 1);
  -- RETURN; -- typically at end of CATCH block when using RAISERROR
END CATCH;
SELECT 2 AS [BB];
GO

Tes 1

EXEC ##Throw;
SELECT 3 AS [CC];

Pengembalian:

"Results" Tab:

DivideByZero
{empty result set}

"Messages" Tab:

Msg 8134, Level 16, State 1, Procedure ##Throw, Line 38
Divide by zero error encountered.

Tes 2

EXEC ##RaisError;
SELECT 4 AS [DD];

Pengembalian:

"Results" Tab:

DivideByZero
{empty result set}

BB
2

DD
4

"Messages" Tab:

Msg 50000, Level 16, State 1, Procedure ##RaisError, Line 45
test, yo!

Agar adil, dimungkinkan untuk menutupi perbedaan ini dengan melakukan hal berikut:

  • Selalu bungkus semua panggilan dengan kode menggunakan THROWdalam TRY...CATCHkonstruksi (ditunjukkan di bawah)
  • Jangan pernah menempatkan kode setelah THROW(well, kecuali untuk END CATCH;)

Tes 3

BEGIN TRY
  EXEC ##Throw;
  SELECT 5 AS [EE];
END TRY
BEGIN CATCH
  SELECT ERROR_NUMBER() AS [ErrorNumber], ERROR_MESSAGE() AS [ErrorMessage];
END CATCH;
SELECT 6 AS [FF];
GO

Pengembalian:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
8134            Divide by zero error encountered.

FF
6

Tes 4

BEGIN TRY
  EXEC ##RaisError;
  SELECT 7 AS [GG];
END TRY
BEGIN CATCH
  SELECT ERROR_NUMBER() AS [ErrorNumber], ERROR_MESSAGE() AS [ErrorMessage];
END CATCH;
SELECT 8 AS [HH];
GO

Pengembalian:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
50000           test, yo!

HH
8
Solomon Rutzky
sumber
3

Saya percaya jawaban Martin Smith hampir 100% benar.

Satu-satunya cara untuk melakukan ini adalah dengan SQL dinamis, dan Anda harus menduplikasi sejumlah besar kode Anda dengan membungkus semua blok coba / tangkap Anda (atau seluruh pernyataan prosedur pembuatan jika Anda akan memiliki dua versi dari semua mereka) yang mengeksekusi tergantung pada versi.

Itu akan menjadi mimpi buruk untuk dipertahankan. Jangan lakukan itu.

Apakah ada cara untuk menjalankan pernyataan SQL berdasarkan versi SQL Server?

SqlZim
sumber