Come interrompere l'esecuzione di script SQL


16

Sto lavorando su SQL Script e ho l'obbligo di interrompere la prosecuzione dello script se alcune condizioni non sono soddisfatte.

Quando lo eseguo su Google, ho scoperto che RaisError con 20 livelli di gravità lo interromperà. Ma per alcuni motivi non posso usare questa opzione.

Per favore, mi può fornire quali sono le possibili alternative per interrompere l'esecuzione di script SQL.


1
Perché l'innalzamento di un errore è inaccettabile? Anche questo script è una procedura memorizzata?
Namphibian,

Non ho capito bene la tua domanda sul pugno. Per la seconda domanda; no, questo non è un SP
Nuovo sviluppatore,

1
Qual è la sceneggiatura? Comprende più lotti? Hai visto le risposte qui?
Martin Smith,

Risposte:


8

Dalla documentazione RAISERROR (sottolineatura mia):

I livelli di gravità da 0 a 18 possono essere specificati da qualsiasi utente. I livelli di gravità da 19 a 25 possono essere specificati solo dai membri del ruolo predefinito del server sysadmin o dagli utenti con autorizzazioni ALTER TRACE. Per i livelli di gravità da 19 a 25, è richiesta l'opzione WITH LOG.

È molto probabile che il principale che stai eseguendo lo script non soddisfi questi criteri.

Non c'è niente di sbagliato nell'uso RAISERROR; stai solo usando un livello di gravità eccessivo. Uso il livello 16 come predefinito per un errore che viene generato e la sequenza verrà terminata. Se vuoi essere più preciso, puoi seguire i livelli indicati dalla stessa Microsoft:

inserisci qui la descrizione dell'immagine

Ora, detto tutto ciò, a seconda del contesto dello script, l'utilizzo RAISERRORpotrebbe non essere sufficiente, in quanto non "esce" dallo script da solo (utilizzando livelli di gravità normali).

Per esempio:

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

SELECT 1;   /* Executed! */

Ciò sia genererà un errore e restituire un set di risultati.

Per terminare immediatamente lo script, preferisco usare RETURN(l'uso di GOTOcostrutti di tipo è generalmente sconsigliato nella maggior parte dei circoli di programmazione in cui esistono alternative):

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

SELECT 1;   /* Not executed */

Oppure gestisci l'errore usando TRY/CATCH, che farà saltare l'esecuzione al CATCHblocco se la gravità è 11 o superiore:

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

Un problema separato è se lo script si estende su più batch - RETURNuscirà solo dal batch :

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

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

Per risolvere questo problema, puoi controllare @@ERRORall'inizio di ogni batch:

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

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
    RETURN;

SELECT 2;   /* Not executed */

Modifica: come sottolinea correttamente Martin Smith nei commenti, questo funziona solo per 2 lotti. Per estendere a 3 o più batch, è possibile generare in sequenza errori di generazione in questo modo (nota: il GOTOmetodo non risolve questo problema poiché l'etichetta di destinazione deve essere definita all'interno del batch):

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

Oppure, come sottolinea anche, puoi usare il SQLCMDmetodo se è appropriato per il tuo ambiente.


L'ultimo suggerimento non funziona. Vedi pastebin . Mi piace il metodo sqlcmd qui
Martin Smith,

6

Puoi utilizzare la GOTOdichiarazione per saltare ovunque tu voglia. In altre parole, ti imbatti in un errore o in qualche altra condizione e puoi avere un'etichetta in fondo allo script (cioè TheEndOfTheScript:) ed emettere semplicemente goto TheEndOfTheScript;un'istruzione.

Ecco un breve esempio:

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

L'output di questa esecuzione sarà il seguente:

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

Come puoi vedere, GOTOha saltato la stampa della terza e della quarta istruzione e è passato direttamente all'etichetta ( TheEndOfTheScript).


7
Funziona solo quando c'è un singolo batch, si interromperà non appena avrai un'istruzione GO.
Gabriel


0

Concordo con SET NOEXEC ON/OFF, comunque in Stored Procs (contenente un singolo blocco) uso semplicemente l' RETURNaffermazione.

Avvertenze: in un file di script, se si hanno più GOistruzioni, RETURNuscirà solo dal blocco corrente e si continuerà con il blocco / batch successivo.

Nota: GOTOsi suppone che sia una cattiva pratica di codifica, TRY..CATCHsi consiglia l' uso di " ", poiché è stato introdotto da SQL Server 2008, seguito da THROWnel 2012.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.