Comment interrompre l'exécution d'un script SQL

16

Je travaille sur le script sql et je dois arrêter de continuer le script si certaines conditions ne sont pas remplies.

Lorsque je le recherche sur Google, j'ai trouvé que la RaisError avec un niveau de gravité de 20 y mettrait fin. Mais pour certaines raisons, je ne peux pas utiliser cette option.

Pouvez-vous me fournir quelles sont les alternatives possibles pour arrêter l'exécution du script SQL.

Nouveau développeur
la source
1
Pourquoi une erreur est-elle inacceptable? Ce script est-il également une procédure stockée?
Namphibian
Je n'ai pas bien compris votre première question. Pour la deuxième question; non ce n'est pas un SP
Nouveau développeur
1
Quel est le script? Comprend-il plusieurs lots? Avez-vous vu les réponses ici?
Martin Smith

Réponses:

8

De la documentation RAISERROR (soulignement le mien):

Les niveaux de gravité de 0 à 18 peuvent être spécifiés par n'importe quel utilisateur. Les niveaux de gravité de 19 à 25 ne peuvent être spécifiés que par les membres du rôle serveur fixe sysadmin ou les utilisateurs disposant des autorisations ALTER TRACE. Pour les niveaux de gravité de 19 à 25, l'option WITH LOG est requise.

Il est fort probable que le principal que vous exécutez le script ne remplit pas ces critères.

Il n'y a rien de mal à utiliser RAISERROR; vous utilisez simplement un niveau de gravité excessif. J'utilise le niveau 16 par défaut pour une erreur qui est déclenchée et la séquence sera terminée. Si vous voulez être plus précis, vous pouvez suivre les niveaux donnés par Microsoft lui-même:

entrez la description de l'image ici

Maintenant, après avoir dit tout cela, selon le contexte du script, l'utilisation RAISERRORpeut ne pas être suffisante, car elle ne "quitte" pas le script lui-même (en utilisant des niveaux de gravité normaux).

Par exemple:

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

SELECT 1;   /* Executed! */

Cela provoquera à la fois une erreur et retournera un jeu de résultats.

Pour terminer le script immédiatement, je préfère utiliser RETURN(l'utilisation de GOTOconstructions de type est généralement déconseillée dans la plupart des cercles de programmation où des alternatives existent):

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

SELECT 1;   /* Not executed */

Ou gérez l'erreur à l'aide de TRY/CATCH, ce qui provoquera l'exécution pour sauter au CATCHbloc si la gravité est 11 ou plus:

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 problème distinct est si le script s'étend sur plusieurs lots - RETURNne quittera que le lot :

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

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

Pour résoudre ce problème, vous pouvez vérifier @@ERRORau début de chaque lot:

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

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
    RETURN;

SELECT 2;   /* Not executed */

Edit: Comme Martin Smith le souligne correctement dans les commentaires, cela ne fonctionne que pour 2 lots. Pour étendre à 3 lots ou plus, vous pouvez cascader des erreurs de génération comme ceci (remarque: la GOTOméthode ne résout pas ce problème car l'étiquette cible doit être définie dans le lot):

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

Ou, comme il le souligne également, vous pouvez utiliser la SQLCMDméthode si cela convient à votre environnement.

Jon Seigel
la source
Cette dernière suggestion ne fonctionne pas. Voir pastebin . J'aime la méthode sqlcmd ici
Martin Smith
6

Vous pouvez utiliser l' GOTOinstruction pour sauter partout où vous le souhaitez. En d'autres termes, vous rencontrez une erreur ou une autre condition, et vous pouvez avoir une étiquette au bas du script (c'est-à-dire TheEndOfTheScript:) et simplement émettre une goto TheEndOfTheScript;instruction.

Voici un petit échantillon:

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

Le résultat de cette exécution sera le suivant:

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

Comme vous pouvez le voir, le GOTOa sauté l'impression des troisième et quatrième instructions et a sauté directement sur l'étiquette ( TheEndOfTheScript).

Thomas Stringer
la source
7
Fonctionne uniquement lorsqu'il y a un seul lot, s'arrêtera dès que vous aurez une instruction GO.
Gabriel
0

D'accord avec le SET NOEXEC ON/OFF, cependant dans Stored Procs (contenant un seul bloc) j'utilise simplement la RETURNdéclaration.

Avertissements: dans un fichier de script, si vous avez plusieurs GOinstructions, le RETURNne sortira que du bloc actuel et continuera avec le bloc / lot suivant.

Remarque: GOTOest censé être une mauvaise pratique de codage, l'utilisation de " TRY..CATCH" est recommandée, car elle a été introduite depuis SQL Server 2008, puis THROWen 2012.

Eddie Kumar
la source