Cómo romper la ejecución del script SQL

16

Estoy trabajando en el script sql y tengo el requisito de dejar de continuar el script si no se cumplen algunas condiciones.

Cuando lo busco en Google, descubrí que el RaisError con un nivel de gravedad de 20 lo terminará. Pero por alguna razón no puedo usar esa opción.

Puede proporcionarme cuáles son las posibles alternativas para detener la ejecución del script SQL.

Nuevo desarrollador
fuente
1
¿Por qué es inaceptable generar un error? ¿También es este script un procedimiento almacenado?
Namphibian
No entendí claramente tu primera pregunta. Para la segunda pregunta; no, esto no es un SP
Nuevo desarrollador
1
¿Cuál es el guión? ¿Comprende lotes múltiples? ¿Has visto las respuestas aquí?
Martin Smith

Respuestas:

8

De la documentación de RAISERROR (énfasis mío):

Cualquier usuario puede especificar los niveles de gravedad de 0 a 18. Los niveles de gravedad del 19 al 25 solo pueden ser especificados por miembros de la función fija de servidor sysadmin o usuarios con permisos ALTER TRACE. Para niveles de gravedad del 19 al 25, se requiere la opción WITH LOG.

Es muy probable que el director al que está ejecutando el script no cumpla con estos criterios.

No hay nada de malo en usar RAISERROR; solo estás usando un nivel de severidad que es excesivo. Uso el nivel 16 como valor predeterminado para un error que se genera y la secuencia finalizará. Si desea ser más preciso, puede seguir los niveles dados por el propio Microsoft:

ingrese la descripción de la imagen aquí

Ahora, habiendo dicho todo eso, dependiendo del contexto del guión, el uso RAISERRORpuede no ser suficiente, ya que no "sale" del guión por sí mismo (usando niveles de gravedad normales).

Por ejemplo:

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

SELECT 1;   /* Executed! */

Esto tanto generará un error y devolver un conjunto de resultados.

Para terminar el script de inmediato, prefiero usar RETURN( GOTOgeneralmente se desaconseja el uso de construcciones de tipo en la mayoría de los círculos de programación donde existen alternativas):

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

SELECT 1;   /* Not executed */

O maneje el error usando TRY/CATCH, lo que hará que la ejecución salte al CATCHbloque si la gravedad es 11 o superior:

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

Otro problema es si el script abarca varios lotes RETURN, solo saldrá del lote :

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

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

Para solucionar esto, puede verificar @@ERRORal comienzo de cada lote:

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

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
    RETURN;

SELECT 2;   /* Not executed */

Editar: como Martin Smith señala correctamente en los comentarios, esto solo funciona para 2 lotes. Para extender a 3 o más lotes, puede colocar en cascada los errores de elevación de esta manera (nota: el GOTOmétodo no resuelve este problema ya que la etiqueta de destino debe definirse dentro del lote):

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

O, como él también señala, puede usar el SQLCMDmétodo si es apropiado para su entorno.

Jon Seigel
fuente
Esa última sugerencia no funciona. Ver pastebin . Me gusta el método sqlcmd aquí
Martin Smith
6

Puede utilizar la GOTOdeclaración para saltear donde quiera. En otras palabras, se encuentra con un error o alguna otra condición, y puede tener una etiqueta en la parte inferior del script (es decir TheEndOfTheScript:) y simplemente emitir una goto TheEndOfTheScript;declaración.

Aquí hay una muestra rápida:

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...';

El resultado de esta ejecución será el siguiente:

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

Como puede ver, GOTOse omitió la impresión de las declaraciones tercera y cuarta y saltó directamente a la etiqueta ( TheEndOfTheScript).

Thomas Stringer
fuente
77
Solo funciona cuando hay un solo lote, se romperá tan pronto como tenga una declaración GO.
Gabriel
0

SET NOEXEC ON/OFFEstoy de acuerdo con el , sin embargo, en los procedimientos almacenados (que contienen un solo bloque) simplemente uso la RETURNdeclaración.

Advertencias: en un archivo de script, si tiene varias GOdeclaraciones, RETURNsolo saldrá del bloque actual y continuará con el siguiente bloque / lote.

Nota: GOTOse supone que es una mala práctica de codificación, TRY..CATCHse recomienda el uso de " ", ya que se introdujo desde SQL Server 2008, seguido de THROW2012.

Eddie Kumar
fuente