352 votes

SQL Server - arrêter ou interrompre l'exécution d'un script SQL

Existe-t-il un moyen d'arrêter immédiatement l'exécution d'un script SQL dans le serveur SQL, comme une commande "break" ou "exit" ?

J'ai un script qui fait quelques validations et recherches avant de commencer à faire des insertions, et je veux qu'il s'arrête si l'une des validations ou des recherches échoue.

396voto

Blorgbeard Points 38991

Le site raiserror méthode

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

Cela mettra fin à la connexion, arrêtant ainsi l'exécution du reste du script.

Notez que le niveau de sévérité 20 ou plus et l'option WITH LOG sont nécessaires pour qu'il fonctionne de cette manière.

Cela fonctionne même avec les déclarations GO, par exemple.

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

Vous obtiendrez le résultat :

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.

Notez que "ho" n'est pas imprimé.

CAVEATS :

  • Cela ne fonctionne que si vous êtes connecté en tant qu'administrateur (rôle 'sysadmin'), et vous laisse également sans connexion à la base de données.
  • Si vous n'êtes PAS connecté en tant qu'administrateur, l'appel de RAISEERROR() lui-même échouera. et le script continuera à s'exécuter .
  • Lorsqu'il est invoqué avec sqlcmd.exe, le code de sortie 2745 est signalé.

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

La méthode noexec

Une autre méthode qui fonctionne avec les déclarations GO est set noexec on . Cela fait sauter le reste du script. Cela ne met pas fin à la connexion, mais vous devez transformer la commande noexec avant que toute commande ne soit exécutée.

Exemple :

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.

0 votes

En effet, c'est la seule méthode qui fonctionne avec plusieurs instructions GO, que je dois souvent utiliser dans mes scripts de mise à jour de bases de données. Merci !

14 votes

C'est génial ! C'est un peu une approche "gros bâton", mais il y a des moments où vous en avez vraiment besoin. Notez que cela nécessite à la fois la sévérité 20 (ou plus) et "WITH LOG".

6 votes

Notez qu'avec la méthode noexec le reste du script est toujours interprété, donc vous obtiendrez toujours des erreurs de compilation, telles que la colonne n'existe pas. Si vous voulez traiter conditionnellement les changements de schéma connus impliquant des colonnes manquantes en sautant une partie du code, la seule façon que je connaisse pour le faire est d'utiliser :r en mode sqlcommand pour référencer des fichiers externes.

198voto

Gordon Bell Points 5798

Utilisez simplement un RETURN (cela fonctionnera aussi bien à l'intérieur qu'à l'extérieur d'une procédure stockée).

2 votes

Pour une raison quelconque, je pensais que le retour ne fonctionnait pas dans les scripts, mais je viens d'essayer, et c'est le cas ! Merci

4 votes

Dans un script, vous ne pouvez pas faire un RETURN avec une valeur comme vous pouvez le faire dans une procédure stockée, mais vous pouvez faire un RETURN.

63 votes

Non, il ne fait que terminer jusqu'au prochain GO Le lot suivant (après GO) s'exécutera comme d'habitude

58voto

Sglasses Points 211

Si vous pouvez utiliser le mode SQLCMD, alors l'incantation

:on error exit

(INCLUANT les deux points) fera en sorte que RAISERROR arrête réellement le script. Par exemple,

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

produira un résultat :

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

et le batch s'arrêtera. Si le mode SQLCMD n'est pas activé, vous obtiendrez une erreur de parse concernant les deux-points. Malheureusement, ce n'est pas complètement à l'épreuve des balles car si le script est exécuté sans être en mode SQLCMD, SQL Managment Studio passe sans problème les erreurs d'analyse syntaxique ! Néanmoins, si vous les exécutez à partir de la ligne de commande, c'est parfait.

6 votes

Excellent commentaire, merci. J'ajouterai que dans SSMS le mode SQLCmd est basculable sous le menu Requête.

0 votes

C'est utile - cela signifie que vous n'avez pas besoin de l'option -b lorsque vous exécutez le programme.

2 votes

Puis l'incantation... mais comment je lance Missle magique ? !

21voto

Dave Swersky Points 25958

Je n'utiliserais pas RAISERROR- SQL a des instructions IF qui peuvent être utilisées à cette fin. Faites votre validation et vos recherches et définissez des variables locales, puis utilisez la valeur des variables dans les instructions IF pour rendre les insertions conditionnelles.

Vous n'auriez pas besoin de vérifier le résultat d'une variable à chaque test de validation. Vous pourriez généralement le faire avec une seule variable drapeau pour confirmer que toutes les conditions sont passées :

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

Même si votre validation est plus complexe, vous ne devriez avoir besoin que de quelques variables indicatrices à inclure dans votre ou vos contrôles finaux.

0 votes

Oui, j'utilise des IFs dans d'autres parties du script, mais je ne veux pas avoir à vérifier chaque variable locale avant d'essayer de faire une insertion. Je préférerais simplement que l'ensemble du script s'arrête et que l'utilisateur soit obligé de vérifier les entrées. (Ceci est juste un script rapide et sale)

4 votes

Je ne sais pas vraiment pourquoi cette réponse a été rejetée, car elle est techniquement correcte, mais ce n'est pas ce que le posteur "veut" faire.

0 votes

Est-il possible d'avoir plusieurs blocs dans Begin..End ? C'est-à-dire STATEMENT ; GO ; STATEMENT ; GO ; etc etc ? J'obtiens des erreurs et je suppose que cela pourrait être la raison.

12voto

Jon Erickson Points 29643

Vous pouvez envelopper votre instruction SQL dans une boucle WHILE et utiliser BREAK si nécessaire.

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

5 votes

J'aime bien ce que ça donne, ça a l'air un peu plus sympa que l'erreur de relance. Il ne faut surtout pas oublier le break à la fin !

2 votes

Vous pouvez également utiliser une variable et la placer immédiatement au début de la boucle pour éviter le "split". DECLARE @ST INT; SET @ST = 1; WHILE @ST = 1; BEGIN; SET @ST = 0; ...; END Plus verbeux, mais bon sang, c'est TSQL de toute façon ;-)

0 votes

C'est ainsi que certaines personnes exécutent goto, mais c'est plus confus à suivre que goto.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X