Domanda

Esiste un modo per interrompere immediatamente l'esecuzione di uno script SQL nel server SQL, come un comando "break" o "exit"?

Ho uno script che esegue alcune convalide e ricerche prima di iniziare a eseguire gli inserimenti e desidero che si interrompa se una qualsiasi delle convalide o ricerche fallisce.

È stato utile?

Soluzione

Il metodo raiserror

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

Ciò interromperà la connessione, interrompendo così l'esecuzione del resto dello script.

Nota che sia il livello di gravità 20 o superiore e l'opzione WITH LOG sono necessari per funzionare in questo modo.

Funziona anche con le dichiarazioni GO, ad es.

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

Ti darà l'output:

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.

Nota che 'ho' non è stampato.

avvertenze:

  • Funziona solo se si è effettuato l'accesso come admin (ruolo 'sysadmin') e non si ha alcuna connessione al database.
  • Se NON si è effettuato l'accesso come amministratore, la chiamata RAISEERROR () stessa non riuscirà e lo script continuerà l'esecuzione .
  • Quando viene invocato con sqlcmd.exe, verrà segnalato il codice di uscita 2745.

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

Il metodo noexec

Un altro metodo che funziona con le istruzioni GO è set noexec on. Questo fa sì che il resto dello script venga ignorato. Non interrompe la connessione, ma è necessario disattivare nuovamente noexec prima che vengano eseguiti i comandi.

Esempio:

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.

Altri suggerimenti

Basta usare un INVIO (funzionerà sia all'interno che all'esterno di una procedura memorizzata).

Se puoi usare la modalità SQLCMD, allora l'incantesimo

:on error exit

(COMPRESO i due punti) farà sì che RAISERROR interrompa effettivamente lo script. Per es.,

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

produrrà:

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

e il batch si fermerà. Se la modalità SQLCMD non è attivata, verrà visualizzato un errore di analisi sui due punti. Sfortunatamente, non è completamente a prova di proiettile, come se lo script venisse eseguito senza essere in modalità SQLCMD, SQL Managment Studio fa passare il tempo anche in caso di errori di analisi! Tuttavia, se li esegui dalla riga di comando, va bene.

Non userei RAISERROR - SQL ha istruzioni IF che possono essere utilizzate per questo scopo. Esegui la tua convalida e le tue ricerche e imposta le variabili locali, quindi usa il valore delle variabili nelle istruzioni IF per rendere condizionali gli inserti.

Non è necessario controllare un risultato variabile di ogni test di convalida. Di solito puoi farlo con una sola variabile flag per confermare tutte le condizioni passate:

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

Anche se la convalida è più complessa, è necessario includere solo alcune variabili flag da includere nei controlli finali.

Ho esteso la soluzione on / off noexec con successo con una transazione per eseguire lo script in un modo tutto o niente.

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

Apparentemente il compilatore " capisce " la variabile @finished nell'IF, anche se si è verificato un errore e l'esecuzione è stata disabilitata. Tuttavia, il valore è impostato su 1 solo se l'esecuzione non è stata disabilitata. Quindi posso eseguire correttamente il commit o il rollback della transazione di conseguenza.

potresti avvolgere la tua istruzione SQL in un ciclo WHILE e usare BREAK se necessario

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

In SQL 2012+ è possibile utilizzare GETTARE.

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

Da MSDN:

Genera un'eccezione e trasferisce l'esecuzione a un blocco CATCH di un costrutto TRY…CATCH ...Se un costrutto TRY…CATCH non è disponibile, la sessione viene terminata.Vengono impostati il ​​numero di riga e la procedura in cui viene sollevata l'eccezione.La gravità è impostata su 16.

È una procedura memorizzata? In tal caso, penso che potresti semplicemente fare un Return, come & Quot; Return NULL & Quot ;;

Ulteriore perfezionamento del metodo Sglasses, le righe sopra indicate impongono l'uso della modalità SQLCMD e treminano lo scirpt se non si utilizza la modalità SQLCMD o si utilizza :on error exit per uscire da qualsiasi errore
CONTEXT_INFO viene utilizzato per tenere traccia dello stato.

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

Suggerirei di racchiudere il blocco di codice appropriato in un blocco try catch. È quindi possibile utilizzare l'evento Raiserror con una severità di 11 per rompere il blocco catch, se lo si desidera. Se si desidera solo aumentare i livelli di gravità ma continuare l'esecuzione all'interno del blocco try, utilizzare una gravità inferiore.

Ha senso?

Saluti, John

[Modificato per includere il riferimento BOL]

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

Puoi modificare il flusso di esecuzione usando le GOTO :

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

/* our code */

EndScript:

puoi utilizzare RAISERROR .

Nessuno di questi funziona con le istruzioni "GO". In questo codice, indipendentemente dal fatto che la gravità sia 10 o 11, si ottiene l'istruzione PRINT finale.

Test script:

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

Risultati:

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

L'unico modo per farlo funzionare è scrivere lo script senza GO istruzioni. A volte è facile. A volte è abbastanza difficile. (Usa qualcosa come IF @error <> 0 BEGIN ....)

Questa era la mia soluzione:

...

BEGIN
    raiserror('Invalid database', 15, 10)
    rollback transaction
    return
END

Puoi usare l'istruzione GOTO. Prova questo. Questo è l'uso completo per te.

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

FinalStatement:
     Select @CoumnName from TableName

Uso sempre RETURN qui, funziona in script o Stored Procedure

Assicurati di ROLLBACK la transazione se ci sei, altrimenti <=> comporterà immediatamente una transazione aperta non impegnata

Grazie per la risposta!

raiserror() funziona bene ma non dovresti dimenticare l'istruzione return altrimenti lo script continua senza errori! (hense raiserror non è un " throwerror " ;-)) e, ovviamente, esegue un rollback se necessario!

<=> è bello dire alla persona che esegue lo script che qualcosa è andato storto.

Se si sta semplicemente eseguendo uno script in Management Studio e si desidera interrompere l'esecuzione o il rollback della transazione (se utilizzato) al primo errore, il modo migliore per calcolare è utilizzare provare a prendere il blocco (da SQL 2005 in poi). Funziona bene in Management Studio se si esegue un file di script. Anche il proc memorizzato può sempre usare questo.

Nel giorno in cui abbiamo usato il seguente ... ha funzionato meglio:

RAISERROR ('Error! Connection dead', 20, 127) WITH LOG
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top