Ist es möglich, je nach SQL Server-Version RAISERROR oder THROW zu wählen?

11

Hier ist mein Code im Moment:

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

Funktioniert hervorragend, es sei denn, es wird auf einem Computer mit SQL 2008 ausgeführt. Ich möchte, dass der CATCH-Block eine Überprüfung der SQL-Version durchführt und THROW ausführt, wenn er gleich oder höher als 2012 ist, und RAISERROR, wenn es 2008 ist Syntaxfehler, und ich frage mich, ob es überhaupt möglich ist. Selbst so etwas Einfaches funktioniert bei mir nicht.

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

Jeder Rat wird geschätzt.

thomasjbarrett
quelle

Antworten:

9

Nein, das ist nicht möglich.

Dies ist in früheren Versionen eine ungültige Syntax und führt zu einem Kompilierungsfehler.

Es ist auch nicht möglich, das THROWin einem EXECinnerhalb des catch-Blocks zu verstecken, da ein parameterloser Wurf direkt im catch enthalten sein muss.

Sie müssten die gewünschte Codeversion entsprechend der Version von SQL Server bereitstellen, auf der Sie bereitstellen (und dies wird leider auch in den mir bekannten SSDT-Tools nicht gut unterstützt - kein Äquivalent zum selektiven Einfügen von Codezeilen bedingte Zusammenstellung)

Martin Smith
quelle
4

Es sollte darauf hingewiesen werden, dass Sie dies (höchstwahrscheinlich) nicht tun möchten , selbst wenn es technisch möglich wäre, zwischen THROWund zu wechseln RAISERROR. Warum? Da die sehr geschickte Fähigkeit des parameterlos , THROWum den Fehler wieder wirft die Verwendung derselben Meldungsnummer (dh Msg 8134statt , Msg Xwo X> = 50000) ist nicht der einzige Unterschied zwischen ihnen: THROWchargen Abbruch während RAISERRORnicht. Dies kann ein wichtiger Verhaltensunterschied sein, wie unten gezeigt.

Versuchsaufbau

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

Test 1

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

Kehrt zurück:

"Results" Tab:

DivideByZero
{empty result set}

"Messages" Tab:

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

Test 2

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

Kehrt zurück:

"Results" Tab:

DivideByZero
{empty result set}

BB
2

DD
4

"Messages" Tab:

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

Um fair zu sein, ist es möglich, diesen Unterschied zu maskieren, indem Sie Folgendes tun:

  • Immer wickelt alle Anrufe unter Verwendung von Code THROWinnerhalb eines TRY...CATCHKonstrukts (demonstrierte unten)
  • Setzen Sie niemals Code nach dem THROW(naja, außer END CATCH;)

Test 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

Kehrt zurück:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
8134            Divide by zero error encountered.

FF
6

Test 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

Kehrt zurück:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
50000           test, yo!

HH
8
Solomon Rutzky
quelle
3

Ich glaube, Martin Smiths Antwort ist fast 100% richtig.

Die einzige Möglichkeit, dies zu tun, ist mit dynamischem SQL, und Sie müssten eine große Menge Ihres Codes duplizieren, indem Sie alle Ihre try / catch-Blöcke (oder die gesamte Anweisung create create) umschließen, wenn Sie zwei Versionen von allen haben möchten diejenigen), die je nach Version ausgeführt werden.

Das wäre ein Albtraum. Tu es nicht.

Gibt es eine Möglichkeit, eine SQL-Anweisung basierend auf der SQL Server-Version auszuführen?

SqlZim
quelle