web-dev-qa-db-fra.com

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

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.

16
New Developer

De la documentation RAISERROR (accent sur 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:

enter image description here

Maintenant, cela étant dit, selon le contexte du script, utiliser RAISERROR peut ne pas être suffisant, car il 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 les deux déclenchera une erreur et renverra un jeu de résultats.

Pour terminer le script immédiatement, je préfère utiliser RETURN (l'utilisation des constructions de type GOTO- 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 en utilisant TRY/CATCH , ce qui fera sauter l'exécution au bloc CATCH 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 que si le script s'étend sur plusieurs lots - RETURN ne quittera que le batch:

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

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

Pour résoudre ce problème, vous pouvez vérifier @@ERROR au 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 méthode GOTO 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 méthode SQLCMD si cela convient à votre environnement.

8
Jon Seigel

Vous pouvez utiliser l'instruction GOTO pour vous déplacer où vous le souhaitez. En d'autres termes, vous rencontrez une erreur ou une autre condition, et vous pouvez avoir une étiquette en bas du script (c'est-à-dire TheEndOfTheScript:) et émettez simplement un goto TheEndOfTheScript; déclaration.

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 GOTO a ignoré l'impression des troisième et quatrième instructions et a sauté directement sur l'étiquette (TheEndOfTheScript).

6
Thomas Stringer
4
Yogesh

D'accord avec le SET NOEXEC ON/OFF, cependant dans les processus stockés (contenant un seul bloc) j'utilise simplement l'instruction RETURN.

Avertissements: dans un fichier de script, si vous avez plusieurs instructions GO, les RETURN ne sortiront que du bloc actuel et continueront avec le bloc/lot suivant.

Remarque: GOTO est censé être une mauvaise pratique de codage, l'utilisation de "TRY..CATCH "est recommandé, car il a été introduit depuis SQL Server 2008, suivi de THROW en 2012.

0
Eddie Kumar