SQL Server-arrêt ou interruption de l'exécution D'un script SQL
y a-t-il un moyen d'arrêter immédiatement l'exécution D'un script SQL dans SQL server, comme une commande" break "ou" exit"?
j'ai un script qui fait quelques validations et recherches avant de commencer à faire des inserts, et je veux qu'il s'arrête si l'une des validations ou des recherches échoue.
18 réponses
Le raiserror méthode
raiserror('Oh no a fatal error', 20, -1) with log
ceci mettra fin à la connexion, empêchant ainsi le reste du script de fonctionner.
notez que le niveau de gravité 20 ou plus et l'option WITH LOG
sont nécessaires pour qu'il fonctionne de cette façon.
cela fonctionne même avec les déclarations de 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.
Remarquez que " ho " est pas imprimé.
mises en garde:
- 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() échouera et le script continuera d'exécuter .
- Lorsqu'il est invoqué avec sqlcmd.EXE, le code de sortie 2745 sera signalé.
la méthode noexec
une autre méthode qui fonctionne avec les instructions GO est set noexec on
. Cela fait sauter le reste du script. Il ne met pas fin à la connexion, mais vous devez désactiver à nouveau noexec
avant l'exécution de toute 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.
il suffit d'utiliser un retour (il 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 le colon) va faire arrêter le script par RAISERROR. 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'
sortira:
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 arrêter. Si le mode SQLCMD n'est pas activé, vous obtiendrez une erreur d'analyse sur le côlon. Malheureusement, ce n'est pas complètement à l'épreuve des balles comme si le script était exécuté sans être en mode SQLCMD, SQL Managment Le Studio brille juste après même les erreurs de temps! Quand même, si vous les faîtes sortir de la ligne de commande, c'est très bien.
Je n'utiliserais pas RAISERROR - SQL a si les déclarations qui peuvent être utilisées à cet effet. Faites vos recherches et validations et définissez des variables locales, puis utilisez la valeur des variables dans les instructions IF pour rendre les inserts conditionnels.
vous n'auriez 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 flag pour confirmer toutes les conditions 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 devriez seulement besoin d'un peu de drapeau des variables à inclure dans votre contrôle final(s).
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
j'ai étendu la solution noexec on/off avec succès avec une transaction pour exécuter le script en 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 à 1 seulement si l'exécution n'a pas été désactivée. Je peux donc engager ou annuler la transaction en conséquence.
en SQL 2012+, vous pouvez utiliser jeter .
THROW 51000, 'Stopping execution because validation failed.', 0;
PRINT 'Still Executing'; -- This doesn't execute with THROW
de MSDN:
soulève une exception et transfère l'exécution à un bloc de capture D'un TRY...CATCH construction ... 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 soulevée sont définis. La sévérité est fixée à 16.
est-ce une procédure enregistrée? Si c'est le cas, je pense que vous pourriez simplement faire un retour, comme "Return NULL";
Plus refinig Sglasses méthode, les lignes de force de l'utilisation de mode SQLCMD, et soit treminates le scirpt si vous n'utilisez pas le mode SQLCMD ou utilise des :on error exit
à la sortie sur une erreur
CONTEXT_INFO est utilisé pour garder une trace de 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-------------
je vous suggère d'envelopper votre bloc de code approprié dans un bloc d'essai. Vous pouvez ensuite utiliser L'événement Raiserror avec une sévérité de 11 afin de casser au bloc catch si vous le souhaitez. Si vous voulez seulement raiserrors mais continuer l'exécution dans le bloc d'essai, utilisez une sévérité plus faible.
ça a un sens?
santé, John
[révisé pour inclure la référence BOL]
http://msdn.microsoft.com/en-us/library/ms175976 (SQL.90).aspx
aucun de ceux-ci ne fonctionne avec des déclarations de "GO". Dans ce code, peu importe si la gravité est 10 ou 11, Vous obtenez la déclaration finale D'impression.
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 déclarations GO
. Parfois, c'est facile. Il est parfois assez difficile. (Utilisez quelque chose comme IF @error <> 0 BEGIN ...
.)
C'était ma solution:
...
BEGIN
raiserror('Invalid database', 15, 10)
rollback transaction
return
END
vous pouvez utiliser la déclaration GOTO. Essayez ceci. C'est l'utilisation complet pour vous.
WHILE(@N <= @Count)
BEGIN
GOTO FinalStateMent;
END
FinalStatement:
Select @CoumnName from TableName
Thx pour la réponse!
raiserror()
fonctionne bien mais vous ne devriez pas oublier la déclaration return
sinon le script continue sans erreur! (hense l'instruction raiserror n'est pas un "throwerror" ;-)) et, bien sûr, faire une restauration en cas de besoin!
raiserror()
est agréable de dire à la personne qui exécute le script que quelque chose a mal tourné.
si vous exécutez simplement un script dans Management Studio, et que vous voulez arrêter l'exécution ou la transaction de roll-back (si utilisée) sur la première erreur, alors la meilleure façon que je compte est d'utiliser le bloc de capture d'essai (SQL 2005 onward). Cela fonctionne bien dans Management studio si vous exécutez un fichier script. Procédure stockée peut toujours l'utiliser également.
j'utilise RETURN
ici tout le temps, travaille dans le script ou Stored Procedure
assurez-vous que vous ROLLBACK
l'opération si vous êtes dans un, sinon RETURN
immédiatement résultera en une opération ouverte non engagée