SQL Server – interrupción de la ejecución de una secuencia de comandos SQL

Hay una manera de detener de inmediato la ejecución de una secuencia de comandos SQL en SQL server, como un «break» o «salida» comando?

Tengo un script que hace la validación de búsquedas y antes de que empiece a hacer las inserciones, y quiero que se pare si alguna de las validaciones o fallan las búsquedas.

InformationsquelleAutor Andy White | 2009-03-18

19 Kommentare

  1. 358

    La raiserror método

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

    Esto va a terminar la conexión, así detener el resto de la secuencia de comandos se ejecute.

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

    Esto también funciona con GO instrucciones, por ejemplo.

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

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

    Aviso de que ‘ho’ no se imprime.

    ADVERTENCIAS:

    • Esto sólo funciona si está conectado como administrador, (‘administrador’ papel), y también te deja sin conexión de base de datos.
    • Si NO ha iniciado sesión como administrador, el RAISEERROR() se llama a sí mismo se producirá y el script seguirá ejecutando.
    • 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

    La noexec método

    Otro método que funciona con GO instrucciones es set noexec on. Esto hace que el resto de la secuencia de comandos para ser saltado. No terminar la conexión, pero usted necesita para convertir noexec antes de comandos se ejecutará.

    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.
    • De hecho, este es el único método que funciona con múltiples IR declaraciones, que tengo que usar a menudo en mi actualización de base de datos de scripts. Gracias!
    • Eso es impresionante! Es un poco de un «big stick» enfoque, pero hay momentos en los que realmente lo necesitan. Tenga en cuenta que esto requiere tanto de la gravedad de 20 (o más) y «CON el REGISTRO».
    • Tenga en cuenta que con noexec método el resto de la secuencia de comandos todavía se interpreta, de manera que usted todavía consigue errores en tiempo de compilación, como la columna no existe. Si desea condicionalmente lidiar con el conocido esquema de los cambios de columnas que faltan por omitir algo de código, la única manera que sé hacer es utilizar :r en sqlcommand modo de hacer referencia a archivos externos.
    • Para generada automáticamente secuencias de comandos de cambio (VS proyecto de Base de datos –> Implementar), NOEXEC es un salvavidas
    • El noexec cosa es grande. Muchas gracias!
    • «Esto va a terminar la conexión» – parece que no, al menos eso es lo que yo estoy viendo.
    • está usted usando la gravedad 20-25? El docs decir «los niveles de Gravedad del 20 al 25 se considera grave. Si un nivel de gravedad se encuentra la conexión del cliente se termina después de recibir el mensaje, y el error se registra en el error y la aplicación se inicia.»
    • «la conexión de cliente termina» ese es el punto, quiero ejecución de secuencias de comandos para detener por completo
    • He encontrado en su reciente pregunta acerca de esto. Parece que no es el raiserror ese es el problema. El catch no disparo, presumiblemente debido a la use se interpreta en tiempo de compilación.
    • tenga cuidado con la subida solución de error – parece que algunas excepciones, no cuentan como adecuada excepciones – es necesario establecer un cierto nivel de gravedad (20+) que puede que no tenga permiso para hacerlo!
    • en realidad, resulta el número mágico que se necesita para este trabajo es de 11 a 18, 10 no es un error/excepción realmente y 18 es el número más alto que se puede establecer de forma fiable
    • Yo estaba tratando de este método y no obtener resultado correcto cuando me di cuenta de que… No es solo un Correo en raiserror…
    • Si desea utilizar esto en un script que se ejecute como un usuario administrador del sistema, asegúrese de que establece la gravedad de 18 años o menor. La secuencia de comandos de continuar la ejecución si.
    • NoExec es deliciosamente elegante Si el comentario anterior acerca de la sintaxis/validación de esquema no impide su uso en su caso. No me puedo imaginar el uso de la raiserror ,20, porque es condicional.
    • No tengo control sobre los derechos de usuario y mi admin piensa que él dio lo suficiente los derechos de administrador ( en una base de datos azure). Aún así, SQL Server me niegue la capacidad de usar >18 gravedad + con registro (no soy sysadmin). La versión con SQLCMD :on error exit está funcionando bien, a pesar de que : stackoverflow.com/a/2590364/479251
    • Puedo confirmar que en mi versión de SQL 2017 Developer Edition que raiserror('Oh no a fatal error', 20, -1) with log en efecto, terminar la conexión (que es apropiado y útil, en mi caso de uso).
    • Tenga en cuenta que el archivo de sql está siendo analizado, y de los errores que faltan columnas dará errores. Usted puede utilizar parseonly para detener el análisis de la secuencia de comandos. Esto funciona de la misma manera como noexec.
    • Yo no lo entiendo. He seguido las instrucciones. Entré en el siguiente SQL después de que cada uno VAYA. IF (XACT_STATE()) <> 1 BEGIN Set NOCOUNT OFF ;THROW 525600, 'Rolling back transaction.', 1 ROLLBACK TRANSACTION; set noexec on END; Pero la ejecución no paraba nunca, y que terminó con tres «deshaciendo la Transacción»s errores provocados. Alguna idea?

  2. 178

    Sólo tiene que utilizar un REGRESO (se va a trabajar dentro y fuera de un procedimiento almacenado).

    • Por alguna razón, estaba pensando que el retorno no trabajar en los guiones, pero yo sólo lo intentó, y lo hace! Gracias
    • En una secuencia de comandos, usted no puede hacer una DEVOLUCIÓN con un valor como usted puede en un procedimiento almacenado, pero se puede hacer una DEVOLUCIÓN.
    • No sólo termina hasta la próxima IR El siguiente lote (después de IR) funcionará como de costumbre
    • Pero se puede ESTABLECER CONTEXT_INFO al final de un lote y comprobar si es lo que se espera en el inicio de la siguiente lote, como se describe en jaraics respuesta.
    • peligroso asumir como va a continuar después de, a continuación, siguiente.
    • GO es un guión de terminator o delimitador; no es de código SQL. GO es sólo una instrucción para que el cliente va a utilizar para enviar el comando a la base de datos motor de una nueva secuencia de comandos de inicio después de la marcha delimitador.
    • Esta es una antigua pregunta, pero sigue siendo relevante. el Uso de REGRESO con un IF/ELSE también permite una cierta información de usuario o iniciar sesión para tomar lugar: IF (SELECT @@SERVERNAME) LIKE ‘%WrongServerName%’ BEGIN SELECT ‘por Favor, encontrar a alguien más para que te ayude con este’ COMO Cmon_Man RETORNO FINAL MÁS SELECCIONE «Continuar…» COMO Very_Good
    • Esta respuesta no ayuda con la pregunta, que es «¿hay una manera de detener de inmediato la ejecución de una secuencia de comandos SQL».

  3. 48

    Si usted puede usar el modo SQLCMD, entonces el conjuro

    :on error exit

    (INCLUYENDO el de colon) hará que RAISERROR realmente detener la secuencia de comandos. E. g.,

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

    de salida será:

    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 SQLCMD mode no está activado, usted obtendrá error de análisis sobre el colon. Desafortunadamente, no es completamente a prueba de balas como si el script se ejecuta sin ser en modo SQLCMD, SQL Managment Studio brisas de la derecha más allá incluso de analizar los errores en tiempo! Aún así, si estás ejecutando desde la línea de comandos, esto está bien.

    • Gran comentario, gracias. Voy a añadir que en SSMS modo SQLCmd es alternar bajo el menú Consulta.
    • esto es útil – significa que usted no tendrá la opción-b cuando se ejecuta
    • a continuación, el conjuro… pero ¿cómo puedo fundición de Magia Missle?!
    • perfecto. no requiere de sysadmin ultra extra de derechos de usuario
  4. 22

    Yo no los uso RAISERROR – SQL SI las instrucciones que se pueden utilizar para este propósito. Hacer su validación y búsquedas y establecer las variables locales, a continuación, utilice el valor de las variables en declaraciones a hacer las inserciones condicional.

    No necesita comprobar una variable de resultado de cada prueba de validación. Usualmente se podía hacer esto con sólo una variable de indicador para confirmar todas las condiciones aprobó:

    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 la validación es más complejo, solo necesitarás un par de bandera de las variables a incluir en el final de cheque(s).

    • Sí, estoy usando ie en otras partes de la secuencia de comandos, pero no quiero tener que comprobar cada variable local antes de tratar de hacer una inserción. Prefiero tener toda la secuencia de comandos de parada, y forzar al usuario a comprobar las entradas. (Esto es sólo una forma rápida y sucia de secuencia de comandos)
    • No estoy muy seguro de por qué esta respuesta ha sido rebajado porque es técnicamente correcto, no lo que el cartel «quiere» hacer.
    • Es posible tener varios bloques dentro de Begin..End? El significado de la DECLARACIÓN; IR; DECLARACIÓN; IR;, etc, etc? Me estoy poniendo de los errores y supongo que podría ser la razón.
    • Esto es mucho más fiable que RAISERROR, especialmente si usted no sabe quién va a ser la ejecución de los scripts y con qué privilegios.
    • Sansom: El único problema que yo veo aquí es que SI la instrucción no funciona si usted está tratando de rama sobre un IR declaración. Este es un gran problema si los guiones se basan en el GO instrucciones (por ejemplo, las instrucciones DDL). Aquí es un ejemplo que funciona sin la primera declaración: declare @i int = 0; if @i=0 begin select '1st stmt in IF block' go end else begin select 'ELSE here' end go
  5. 13

    Me extendió la noexec de encendido/apagado de la solución con éxito a una operación para que se ejecute la secuencia de comandos en un todo o nada de la forma.

    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

    Al parecer, el compilador «entiende» el @terminado variable en el si, incluso SI existe un error y la ejecución fue desactivado. Sin embargo, el valor se establece en 1, sólo si la ejecución no se ha deshabilitado. De ahí que bien puede commit o rollback de la transacción en consecuencia.

    • Yo no lo entiendo. He seguido las instrucciones. Entré en el siguiente SQL después de que cada uno VAYA. IF (XACT_STATE()) <> 1 BEGIN Set NOCOUNT OFF ;THROW 525600, 'Rolling back transaction.', 1 ROLLBACK TRANSACTION; set noexec on END; Pero la ejecución no paraba nunca, y que terminó con tres «deshaciendo la Transacción»s errores provocados. Alguna idea?
  6. 13

    En SQL 2012+, se puede usar TIRO.

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

    De MSDN:

    Plantea una excepción y transfiere la ejecución a un bloque CATCH de una construcción TRY…CATCH … Si una construcción TRY…CATCH no está disponible, finaliza la sesión. El número de línea y el procedimiento por el cual la excepción se establecen. La gravedad es 16.

    • TIRO está destinado a reemplazar RAISERROR, pero no puedes evitar que los lotes subsecuentes en el mismo archivo de secuencia de comandos con ella.
    • Correcto @NReilingh. Que es donde Blorgbeard la respuesta es realmente la única solución. Se requiere administrador de sistemas, aunque (nivel de gravedad 20), y es bastante torpe, si no hay de varios lotes en la secuencia de comandos.
    • conjunto de xact abortar si desea cancelar la actual transcation así.
  7. 12

    usted podría ajustar su instrucción SQL en un bucle while y el uso de DESCANSO 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
    • Me gusta el aspecto de este, parece que es un poco mejor que provocar errores. Definitivamente no quiero olvidar el salto al final!
    • También se puede utilizar una variable y de inmediato en la parte superior del bucle para evitar el «split». DECLARE @ST INT; SET @ST = 1; WHILE @ST = 1; BEGIN; SET @ST = 0; ...; END Más detallado, pero diablos, es TSQL de todos modos 😉
    • Esta es la forma en que algunas personas realizan goto, pero es más confuso para seguir de goto.
    • Este método protege de un inesperado ocasionales IR. Agradecidos.
  8. 8

    Es este un procedimiento almacenado? Si es así, creo que se podría hacer una Devolución, tales como «Return NULL»;

    • Gracias por la respuesta, es bueno saber eso, pero en este caso no es un procedimiento almacenado, sólo un archivo de secuencia de comandos
    • No siempre (aquí estoy buscando). Ver otras respuestas (VAYA viajes que, por una cosa)
  9. 8

    Más refinig Sglasses método, las líneas de arriba de la fuerza el uso de SQLCMD modo, y treminates la scirpt si no se utiliza el modo SQLCMD o utiliza :on error exit para salir en cualquier error

    CONTEXT_INFO se utiliza para mantener un seguimiento de 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-------------
    • Esta es la única manera que he encontrado para evitar el SSMS locura de ser incapaz de abortar la secuencia de comandos. Pero he añadido ‘SET NOEXEC OFF’ en el principio, y ‘CONJUNTO de NOEXEC EN’ si no en el modo SQLCMD, de lo contrario la secuencia real va a seguir a menos que se genere un error en el nivel 20 con registro.
  10. 8

    Puede alterar el flujo de ejecución mediante GOTO declaraciones:

    IF @ValidationResult = 0
    BEGIN
        PRINT 'Validation fault.'
        GOTO EndScript
    END
    
    /* our code */
    
    EndScript:
    • el uso de goto es una manera aceptable para manejar la excepción. Reduce la cantidad de variables y de anidación y no la causa de la desconexión. Probablemente sea preferible a la arcaica manejo de excepciones que SQL Server scripting permite.
  11. 6

    Me permito sugerir que usted envolver su correspondiente bloque de código en un bloque try catch. Usted puede utilizar el Raiserror evento con la gravedad de las 11 con el fin de romper el bloque catch, si lo desea. Si usted sólo quiere raiserrors pero continuar la ejecución del bloque try, a continuación, utilizar una menor gravedad.

    Sentido?

    Saludos,
    Juan

    [Editado para incluir BOL de Referencia]

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

    • Nunca he visto a un try-catch en SQL – ¿te importaría publicar un ejemplo rápido de lo que quieres decir?
    • es nueva para el año 2005. BEGIN TRY { sql_statement | statement_block } END TRY COMENZAR CATCH { sql_statement | statement_block } CATCH [ ; ]
    • Añadió referencia, ejemplo incluido.
    • Bloque TRY-CATCH no permite IR dentro de itelf.
  12. 4

    puede utilizar RAISERROR.

    • Esto no tiene sentido para mí – planteo de un error evitable (suponiendo que estamos hablando de referencial de validación de aquí) es una manera horrible de hacer esto si la validación es posible antes de las inserciones de tener lugar.
    • raiserror puede ser utilizado como un mensaje informativo con una gravedad baja de configuración.
    • La secuencia de comandos continuará a menos que ciertas condiciones establecidas en los aceptadas respuesta se cumplen.
  13. 4

    Ninguna de estas obras con ‘GO’ declaraciones. En este código, independientemente de la gravedad es de 10 o 11, usted consigue el final de la instrucción PRINT.

    Secuencia De Comandos 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 este trabajo es para escribir el guión sin GO declaraciones. A veces es fácil. A veces es bastante difícil. (Usar algo como IF @error <> 0 BEGIN ....)

    • No se puede hacer eso con CREAR PROCEDIMIENTO, etc. Ver mi respuesta para una solución.
    • Blogbeard la solución es grande. He estado trabajando con SQL Server durante años y esta es la primera vez que he visto esto.
  14. 3

    Puede utilizar la instrucción GOTO. Intenta esto. Este es el uso completo para usted.

    WHILE(@N <= @Count)
    BEGIN
        GOTO FinalStateMent;
    END
    
    FinalStatement:
         Select @CoumnName from TableName
    • GOTO se supone que es una mala práctica de codificación, el uso de «TRY..CATCH» es recomendable, ya que fue introducido desde SQL Server 2008, seguido por LANZAR en 2012.
  15. 3

    Yo uso RETURN aquí todo el tiempo, trabaja en la secuencia de comandos o Stored Procedure

    Asegúrese de que usted ROLLBACK la transacción si usted está en uno, de lo contrario RETURN inmediatamente se traducirá en un abrir transacción no confirmada

    • No funciona con una secuencia de comandos que contiene varios lotes (IR declaraciones) – ver mi respuesta de cómo hacer eso.
    • REGRESO solo sale el actual bloque de instrucciones. Si usted está en un bloque FINAL, la ejecución continuará después de la FINAL. Esto significa que usted puede utilizar REGRESAR a la final de la ejecución después de la prueba por alguna afección, ya que siempre va a estar en SI es el FINAL del bloque.
  16. 1

    Thx por la respuesta!

    raiserror() funciona bien, pero no debes olvidar el return declaración, de lo contrario el script continúa sin error! (hense la raiserror no es un «throwerror» ;-)) y por supuesto, haciendo un rollback si es necesario!

    raiserror() es bueno decirle a la persona que ejecuta la secuencia de comandos que algo salió mal.

  17. 1

    Si usted es simplemente la ejecución de un script en Management Studio, y desea detener la ejecución o rollback de la transacción (si se utiliza) en el primer error, entonces la mejor manera creo que es el uso de try catch (bloque de SQL 2005 en adelante).
    Esto funciona bien en el Management studio si se ejecuta un archivo de comandos.
    Procedimiento almacenado puede utilizar siempre esta así.

  18. 0

    De vuelta en el día, hemos utilizado las siguientes…funcionó mejor:

    RAISERROR ('Error! Connection dead', 20, 127) WITH LOG

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea