¿Es posible elegir RAISERROR o THROW dependiendo de la versión de SQL Server?

11

Aquí está mi código en este momento:

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

Funciona muy bien, a menos que se ejecute en una máquina con SQL 2008. Me gustaría que el bloque CATCH verifique la versión de SQL y ejecute THROW si es igual o superior a 2012, y RAISERROR si es 2008. Sigo encontrándome con errores de sintaxis, y me pregunto si es posible. Incluso algo simple como esto no me funciona.

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

Cualquier consejo es apreciado.

thomasjbarrett
fuente

Respuestas:

9

No, esto no es posible.

Esta es una sintaxis no válida en versiones anteriores y provocará un error de compilación.

No es posible ocultar la THROWen un EXECinterior del bloque catch ya sea como un tiro sin parámetros debe estar contenido directamente en el interior de la captura.

Debería implementar la versión de código que desea de acuerdo con la versión de SQL Server que está implementando (y desafortunadamente tampoco hay un buen soporte para esto en las herramientas SSDT que conozco), no hay equivalente a incluir líneas de código selectivamente a través de compilación condicional)

Martin Smith
fuente
4

Cabe señalar que, incluso si fuera técnicamente posible alternar entre THROWy RAISERROR, usted (muy probablemente) no querría hacer esto realmente. ¿Por qué? Debido a que la habilidad muy ingeniosa de los sin parámetros THROWpara volver a lanzar el error usando el mismo Número de Mensaje (es decir, en Msg 8134lugar de Msg Xdonde X> = 50000) no es la única diferencia entre ellos: THROWes abortar por lotes mientras RAISERRORque no lo es. Esta puede ser una diferencia de comportamiento importante como se demuestra a continuación.

Configuración de prueba

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

Prueba 1

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

Devoluciones:

"Results" Tab:

DivideByZero
{empty result set}

"Messages" Tab:

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

Prueba 2

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

Devoluciones:

"Results" Tab:

DivideByZero
{empty result set}

BB
2

DD
4

"Messages" Tab:

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

Para ser justos, es posible enmascarar esta diferencia haciendo lo siguiente:

  • Siempre envuelva todas las llamadas al código utilizando THROWuna TRY...CATCHconstrucción (se muestra a continuación)
  • Nunca coloque el código después del THROW(bueno, excepto END CATCH;)

Prueba 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

Devoluciones:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
8134            Divide by zero error encountered.

FF
6

Prueba 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

Devoluciones:

"Results" Tab:

DivideByZero
{empty result set}

ErrorNumber     ErrorMessage
50000           test, yo!

HH
8
Solomon Rutzky
fuente
3

Creo que la respuesta de Martin Smith es casi 100% correcta.

La única forma de hacerlo es con SQL dinámico, y tendrías que duplicar una gran cantidad de tu código envolviendo todos tus bloques try / catch (o toda la declaración del procedimiento de creación si vas a tener dos versiones de todos aquellos) que se ejecutan según la versión.

Eso sería una pesadilla para mantener. No lo hagas

¿Hay alguna manera de ejecutar una declaración SQL basada en la versión de SQL Server?

SqlZim
fuente