Existe-t-il un moyen d'arrêter immédiatement l'exécution d'un script SQL sur le serveur SQL, comme une commande "break" ou "exit"?
J'ai un script qui effectue des validations et des recherches avant de commencer à insérer des insertions, et je souhaite qu'il s'arrête si l'une des validations ou recherches échoue.
Le raiserror method
raiserror('Oh no a fatal error', 20, -1) with log
Cela mettra fin à la connexion, empêchant ainsi l'exécution du reste du script.
Notez que le niveau de gravité 20 ou supérieur et l’option WITH LOG
sont nécessaires pour que cela fonctionne de cette façon.
Cela fonctionne même avec les instructions GO, par exemple.
print 'hi'
go
raiserror('Oh no a fatal error', 20, -1) with log
go
print 'ho'
Vous donnera la sortie:
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:
La méthode noexec
Une autre méthode qui fonctionne avec les instructions GO est set noexec on
. Cela provoque le saut du reste du script. Il ne met pas fin à la connexion, mais vous devez désactiver noexec
avant de pouvoir exécuter une commande.
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.
Utilisez simplement un RETURN (cela fonctionnera à la fois à l'intérieur et à l'extérieur d'une procédure stockée).
Si vous pouvez utiliser le mode SQLCMD, alors l’incantation
:on error exit
(Y compris les deux points), RAISERROR arrêtera 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'
affichera:
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 lot va s'arrêter. Si le mode SQLCMD n'est pas activé, vous obtiendrez une erreur d'analyse concernant les deux points. Malheureusement, comme si le script était exécuté sans être en mode SQLCMD, SQL Managment Studio passe au-delà des erreurs de temps d'analyse! Néanmoins, si vous les exécutez à partir de la ligne de commande, tout va bien.
Je n'utiliserais pas RAISERROR- SQL comporte des instructions IF pouvant ê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'avez pas besoin de vérifier un résultat variable de chaque test de validation. Vous pouvez généralement le faire avec une seule variable indicateur pour confirmer que toutes les conditions sont remplies:
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 n’auriez besoin que de quelques variables indicatrices à inclure dans vos vérifications finales.
Dans SQL 2012+, vous pouvez utiliser THROW .
THROW 51000, 'Stopping execution because validation failed.', 0;
PRINT 'Still Executing'; -- This doesn't execute with THROW
De MSDN:
Lève une exception et transfère l'exécution à un bloc CATCH d'une construction TRY… CATCH ... Si une construction TRY… CATCH n'est pas disponible, la session est terminée. Le numéro de ligne et la procédure où l'exception est levée sont définis. La gravité est définie sur 16.
J'ai étendu la solution noexec on/off avec succès avec une transaction permettant d'exécuter le script de manière tout ou rien.
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
Apparemment, le compilateur "comprend" la variable @finished dans le SI, même s'il y avait une erreur et que l'exécution était désactivée. Cependant, la valeur est définie sur 1 uniquement si l'exécution n'a pas été désactivée. Par conséquent, je peux bien valider ou annuler la transaction en conséquence.
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
En plus de la méthode Sglasses de raffinement, les lignes ci-dessus forcent l’utilisation du mode SQLCMD, et transfèrent le scirpt si le mode SQLCMD n’est pas utilisé ou utilisent :on error exit
pour sortir de toute erreur
CONTEXT_INFO est utilisé pour suivre l’état.
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-------------
Est-ce une procédure stockée? Si c'est le cas, je pense que vous pouvez simplement faire un retour, tel que "Return NULL";
Je suggérerais que vous encapsuliez votre bloc de code approprié dans un bloc catch catch. Vous pouvez ensuite utiliser l'événement Raiserror avec une sévérité de 11 afin de passer au bloc catch si vous le souhaitez. Si vous souhaitez simplement expliquer des erreurs mais poursuivre l'exécution dans le bloc try, utilisez une gravité inférieure.
Avoir un sens?
A bientôt, John
[Édité pour inclure BOL Reference]
http://msdn.Microsoft.com/en-us/library/ms175976(SQL.90).aspx
Vous pouvez modifier le flux d'exécution à l'aide de GOTO statement:
IF @ValidationResult = 0
BEGIN
PRINT 'Validation fault.'
GOTO EndScript
END
/* our code */
EndScript:
Aucun de ces travaux avec les déclarations «GO». Dans ce code, que la gravité soit 10 ou 11, vous obtenez l'instruction PRINT finale.
Script de test:
-- =================================
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
Résultats:
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
La seule façon de faire ce travail est d'écrire le script sans les instructions GO
. Parfois c'est facile. Parfois c'est assez difficile. (Utilisez quelque chose comme IF @error <> 0 BEGIN ...
.)
vous pouvez utiliser RAISERROR .
C'était ma solution:
...
BEGIN
raiserror('Invalid database', 15, 10)
rollback transaction
return
END
Vous pouvez utiliser l'instruction GOTO. Essaye ça. C'est une utilisation complète pour vous.
WHILE(@N <= @Count)
BEGIN
GOTO FinalStateMent;
END
FinalStatement:
Select @CoumnName from TableName
J'utilise RETURN
ici tout le temps, fonctionne en script ou Stored Procedure
Assurez-vous que vous avez ROLLBACK
la transaction si vous en avez une, sinon RETURN
entraînera immédiatement une transaction ouverte non validée.
Merci pour la réponse!
raiserror()
fonctionne bien, mais vous ne devez pas oublier la déclaration return
sinon le script continue sans erreur! (car le raiserror n'est pas un "throwerror" ;-)) et bien sûr faire un retour en arrière si nécessaire!
raiserror()
est agréable à dire à la personne qui exécute le script que quelque chose s'est mal passé.
Si vous exécutez simplement un script dans Management Studio et souhaitez arrêter l'exécution ou la transaction d'annulation (si elle est utilisée) à la première erreur, le meilleur moyen, à mon avis, est d'utiliser try catch block (SQL 2005 et ultérieur) . bien en studio de gestion si vous exécutez un fichier de script . proc stocké peut toujours l'utiliser aussi.
De retour dans la journée, nous utilisions les éléments suivants ... qui fonctionnaient le mieux:
RAISERROR ('Error! Connection dead', 20, 127) WITH LOG