SQL Server-detener o interrumpir la ejecución de un script SQL


¿Hay alguna forma de detener inmediatamente la ejecución de un script SQL en SQL server, como un comando "break" o "exit"?

Tengo un script que hace algunas validaciones y búsquedas antes de comenzar a hacer inserciones, y quiero que se detenga si alguna de las validaciones o búsquedas falla.

Author: Blorgbeard, 2009-03-18

18 answers

El método raiserror

raiserror('Oh no a fatal error', 20, -1) with log

Esto terminará la conexión, deteniendo así la ejecución del resto del script.

Tenga en cuenta que tanto el nivel de gravedad 20 o superior como la opción WITH LOG son necesarios para que funcione de esta manera.

Esto incluso funciona con declaraciones GO, por ejemplo.

print 'hi'
go
raiserror('Oh no a fatal error', 20, -1) with log
go
print 'ho'

Te dará la salida:

hi
Msg 2745, Level 16, State 2, Line 1
Process ID 51 has raised user error 50000, severity 20. SQL Server is terminating this process.
Msg 50000, Level 20, State 1, Line 1
Oh no a fatal error
Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command.  The results, if any, should be discarded.

Observe que 'ho' no está impreso.

ADVERTENCIAS:

  • Esto solo funciona si está registrado en as admin (rol' sysadmin'), y también te deja sin conexión a la base de datos.
  • Si NO estás conectado como administrador, la llamada RAISEERROR() fallará y el script continuará ejecutándose.
  • Cuando se invoca con sqlcmd.exe, código de salida 2745 será reportado.

Referencia: http://www.mydatabasesupport.com/forums/ms-sqlserver/174037-sql-server-2000-abort-whole-script.html#post761334

El noexec método

Otro método que funciona con sentencias GO es set noexec on. Esto hace que el resto del script se omita. No termina la conexión, pero debe desactivar noexec de nuevo antes de que se ejecuten los comandos.

Ejemplo:

print 'hi'
go

print 'Fatal error, script will not continue!'
set noexec on

print 'ho'
go

-- last line of the script
set noexec off -- Turn execution back on; only needed in SSMS, so as to be able 
               -- to run this script again in the same session.
 312
Author: Blorgbeard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-18 16:43:00

Simplemente use un RETORNO (funcionará tanto dentro como fuera de un procedimiento almacenado).

 153
Author: Gordon Bell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 17:23:19

Si puedes usar el modo SQLCMD, entonces el encantamiento

:on error exit

(INCLUYENDO los dos puntos) hará que RAISERROR detenga realmente el script. Por ejemplo,

:on error exit

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SOMETABLE]') AND type in (N'U')) 
    RaisError ('This is not a Valid Instance Database', 15, 10)
GO

print 'Keep Working'

Producirá:

Msg 50000, Level 15, State 10, Line 3
This is not a Valid Instance Database
** An error was encountered during execution of batch. Exiting.

Y el lote se detendrá. Si el modo SQLCMD no está activado, obtendrá un error de análisis sobre los dos puntos. Desafortunadamente, no es completamente a prueba de balas como si el script se ejecuta sin estar en modo SQLCMD, SQL Managment Studio breezes justo pasado incluso analizar errores de tiempo! Aún así, si estás corriendo desde la línea de comandos, esto está bien.

 41
Author: Sglasses,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-07 06:13:39

No usaría sentencias RAISERROR - SQL has IF que se puedan usar para este propósito. Haga su validación y búsquedas y establezca variables locales, luego use el valor de las variables en sentencias IF para hacer las inserciones condicionales.

No es necesario comprobar un resultado variable de cada prueba de validación. Por lo general, puede hacer esto con una sola variable de bandera para confirmar todas las condiciones pasadas:

declare @valid bit

set @valid = 1

if -- Condition(s)
begin
  print 'Condition(s) failed.'
  set @valid = 0
end

-- Additional validation with similar structure

-- Final check that validation passed
if @valid = 1
begin
  print 'Validation succeeded.'

  -- Do work
end

Incluso si su validación es más compleja, solo debería necesitar unas pocas marcas variables a incluir en su(s) comprobación (es) final (es).

 20
Author: Dave Swersky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-17 11:24:33

Puede envolver su sentencia SQL en un bucle WHILE y usar BREAK si es necesario

WHILE 1 = 1
BEGIN
   -- Do work here
   -- If you need to stop execution then use a BREAK


    BREAK; --Make sure to have this break at the end to prevent infinite loop
END
 12
Author: Jon Erickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 17:27:14

Extendí la solución on/off de noexec con éxito con una transacción para ejecutar el script de una manera de todo o nada.

set noexec off

begin transaction
go

<First batch, do something here>
go
if @@error != 0 set noexec on;

<Second batch, do something here>
go
if @@error != 0 set noexec on;

<... etc>

declare @finished bit;
set @finished = 1;

SET noexec off;

IF @finished = 1
BEGIN
    PRINT 'Committing changes'
    COMMIT TRANSACTION
END
ELSE
BEGIN
    PRINT 'Errors occured. Rolling back changes'
    ROLLBACK TRANSACTION
END

Aparentemente el compilador "entiende" la variable @finished en el IF, incluso si hubo un error y la ejecución fue deshabilitada. Sin embargo, el valor se establece en 1 solo si la ejecución no se deshabilitó. Por lo tanto, puedo confirmar o revertir la transacción en consecuencia.

 11
Author: Tz_,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-25 12:27:31

En SQL 2012+, puede usar THROW.

THROW 51000, 'Stopping execution because validation failed.', 0;
PRINT 'Still Executing'; -- This doesn't execute with THROW

De MSDN:

Genera una excepción y transfiere la ejecución a un bloque CATCH de una construcción TRY CATCH CATCH ... Si una construcción TRY CATCH CATCH no está disponible, la sesión finaliza. Se establece el número de línea y el procedimiento donde se genera la excepción. La gravedad se establece en 16.

 11
Author: Jordan Parker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-19 16:21:15

Es este un procedimiento almacenado? Si es así, creo que podría hacer un Retorno, como"Return NULL";

 7
Author: mtazva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 17:07:52

Además refinig Sglasses método, las líneas anteriores fuerzan el uso del modo SQLCMD, y ya sea treminates el scirpt si no se utiliza el modo SQLCMD o utiliza :on error exit para salir en cualquier error
CONTEXT_INFO se utiliza para realizar un seguimiento del estado.

SET CONTEXT_INFO  0x1 --Just to make sure everything's ok
GO 
--treminate the script on any error. (Requires SQLCMD mode)
:on error exit 
--If not in SQLCMD mode the above line will generate an error, so the next line won't hit
SET CONTEXT_INFO 0x2
GO
--make sure to use SQLCMD mode ( :on error needs that)
IF CONTEXT_INFO()<>0x2 
BEGIN
    SELECT CONTEXT_INFO()
    SELECT 'This script must be run in SQLCMD mode! (To enable it go to (Management Studio) Query->SQLCMD mode)\nPlease abort the script!'
    RAISERROR('This script must be run in SQLCMD mode! (To enable it go to (Management Studio) Query->SQLCMD mode)\nPlease abort the script!',16,1) WITH NOWAIT 
    WAITFOR DELAY '02:00'; --wait for the user to read the message, and terminate the script manually
END
GO

----------------------------------------------------------------------------------
----THE ACTUAL SCRIPT BEGINS HERE-------------
 7
Author: jaraics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-24 15:55:50

Sugeriría que envuelva su bloque de código apropiado en un bloque try catch. A continuación, puede utilizar el evento Raiserror con una gravedad de 11 con el fin de romper al bloque catch si lo desea. Si solo desea raiserrors pero continuar la ejecución dentro del bloque try, use una severidad menor.

¿Tiene sentido?

Saludos, John

[Editado para incluir la referencia BOL]

Http://msdn.microsoft.com/en-us/library/ms175976 (SQL. 90). aspx

 6
Author: John Sansom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-19 12:29:49

Puede usar RAISERROR.

 5
Author: Mladen Prajdic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-18 17:05:27

Puede alterar el flujo de ejecución usando instrucciones GOTO :

IF @ValidationResult = 0
BEGIN
    PRINT 'Validation fault.'
    GOTO EndScript
END

/* our code */

EndScript:
 5
Author: Charlie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-09 15:21:25

Ninguno de estos trabajos con declaraciones 'GO'. En este código, independientemente de si la gravedad es 10 o 11, se obtiene la sentencia PRINT final.

Script de prueba:

-- =================================
PRINT 'Start Test 1 - RAISERROR'

IF 1 = 1 BEGIN
    RAISERROR('Error 1, level 11', 11, 1)
    RETURN
END

IF 1 = 1 BEGIN
    RAISERROR('Error 2, level 11', 11, 1)
    RETURN
END
GO

PRINT 'Test 1 - After GO'
GO

-- =================================
PRINT 'Start Test 2 - Try/Catch'

BEGIN TRY
    SELECT (1 / 0) AS CauseError
END TRY
BEGIN CATCH
    SELECT ERROR_MESSAGE() AS ErrorMessage
    RAISERROR('Error in TRY, level 11', 11, 1)
    RETURN
END CATCH
GO

PRINT 'Test 2 - After GO'
GO

Resultados:

Start Test 1 - RAISERROR
Msg 50000, Level 11, State 1, Line 5
Error 1, level 11
Test 1 - After GO
Start Test 2 - Try/Catch
 CauseError
-----------

ErrorMessage
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Divide by zero error encountered.

Msg 50000, Level 11, State 1, Line 10
Error in TRY, level 11
Test 2 - After GO

La única manera de hacer que esto funcione es escribir el script sin instrucciones GO. A veces es fácil. A veces es bastante difícil. (Usa algo como IF @error <> 0 BEGIN ....)

 4
Author: Rob Garrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-27 12:59:20

Esta fue mi solución:

...

BEGIN
    raiserror('Invalid database', 15, 10)
    rollback transaction
    return
END
 3
Author: Casper Leon Nielsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-27 08:40:44

Puede usar la instrucción GOTO. Prueba esto. Este es el uso completo para usted.

WHILE(@N <= @Count)
BEGIN
    GOTO FinalStateMent;
END

FinalStatement:
     Select @CoumnName from TableName
 2
Author: Vishal Kiri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-07 06:58:18

Gracias por la respuesta!

raiserror() funciona bien, pero no debe olvidar la instrucción return de lo contrario, el script continúa sin error! (hense el raiserror no es un "throwerror"; -)) y por supuesto hacer una reversión si es necesario!

raiserror() es bueno decirle a la persona que ejecuta el guión que algo salió mal.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-31 13:52:18

Si simplemente está ejecutando un script en Management Studio, y desea detener la ejecución o revertir la transacción (si se usa) en el primer error, entonces la mejor manera que considero es usar try catch block (SQL 2005 en adelante). Esto funciona bien en Management studio si está ejecutando un archivo de script. El proc almacenado siempre puede usar esto también.

 1
Author: Bhargav Shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-05 07:34:31

Uso RETURN aquí todo el tiempo, funciona en script o Stored Procedure

Asegúrese de que ROLLBACK la transacción si está en una, de lo contrario RETURN inmediatamente resultará en una transacción abierta no comprometida

 1
Author: jerryhung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-28 19:02:36