Có thể chọn RAISERROR hoặc THWAY tùy thuộc vào phiên bản SQL Server không?


11

Đây là mã của tôi ngay bây giờ:

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

Hoạt động rất tốt, trừ khi nó chạy trên máy có SQL. Tôi muốn có khối CATCH kiểm tra phiên bản SQL và chạy TÊN nếu nó bằng hoặc cao hơn năm 2012 và RAISERROR nếu là năm 2008. lỗi cú pháp, và tôi tự hỏi nếu nó thậm chí có thể. Ngay cả những thứ đơn giản như thế này cũng không hiệu quả với tôi.

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

Bất kỳ lời khuyên được đánh giá cao.

Câu trả lời:


9

Không, điều này là không thể.

Đây là cú pháp không hợp lệ trong các phiên bản trước và sẽ gây ra lỗi biên dịch.

Không thể che giấu THROW trong một EXECbên trong khối catch hoặc như một ném parameterless phải được chứa trực tiếp bên trong việc nắm bắt.

Bạn sẽ cần triển khai phiên bản mã bạn muốn theo phiên bản SQL Server mà bạn đang triển khai (và thật không may, không có hỗ trợ tốt nào cho công cụ SSDT mà tôi biết - không tương đương bao gồm các dòng mã có chọn lọc thông qua biên soạn có điều kiện)


4

Cần phải chỉ ra rằng, ngay cả khi về mặt kỹ thuật có thể xen kẽ giữa THROWRAISERROR, rất có thể bạn sẽ không muốn thực sự làm điều này. Tại sao? Bởi vì khả năng rất tiện lợi của việc không tham số THROWđể ném lại lỗi bằng cách sử dụng cùng một Số Thông báo (nghĩa là Msg 8134thay vì trong Msg Xđó X> = 50000) không phải là điểm khác biệt duy nhất giữa chúng: THROWlà hủy bỏ hàng loạt trong khiRAISERROR không phải là . Đây có thể là một sự khác biệt quan trọng về hành vi như được trình bày dưới đây.

Kiểm tra cài đặt

--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

Kiểm tra 1

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

Trả về:

"Results" Tab:

DivideByZero
{empty result set}

"Messages" Tab:

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

Kiểm tra 2

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

Trả về:

"Results" Tab:

DivideByZero
{empty result set}

BB
2

DD
4

"Messages" Tab:

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

Để công bằng, có thể che giấu sự khác biệt này bằng cách làm như sau:

  • Luôn luôn bọc tất cả các cuộc gọi đến mã bằng cách sử dụng THROWtrong mộtTRY...CATCH cấu trúc (được trình bày bên dưới)
  • Không bao giờ đặt mã sau THROW(tốt, ngoại trừ END CATCH;)

Bài kiểm tra 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

Trả về:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
8134            Divide by zero error encountered.

FF
6

Kiểm tra 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

Trả về:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
50000           test, yo!

HH
8

3

Tôi tin rằng câu trả lời của Martin Smith gần như đúng 100%.

Cách duy nhất để làm điều này là với SQL động và bạn sẽ phải sao chép một lượng lớn mã bằng cách gói tất cả các khối thử / bắt (hoặc toàn bộ câu lệnh tạo thủ tục nếu bạn sắp có hai phiên bản của tất cả những cái đó) thực thi tùy thuộc vào phiên bản.

Đó sẽ là một cơn ác mộng để duy trì. Đừng làm điều đó.

Có cách nào để thực thi câu lệnh SQL dựa trên phiên bản SQL Server không?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.