Comment puis-je quitter au milieu d'une procédure stockée?
J'ai une procédure stockée dans laquelle je veux sortir plus tôt (en essayant de la déboguer). J'ai essayé d'appeler RETURN
et RAISERROR
, et le sp continue à fonctionner:
CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS
print 'before raiserror'
raiserror('this is a raised error', 18, 1)
print 'before return'
return -1
print 'after return'
[snip]
Je sais qu'il continue à fonctionner parce que je rencontre une erreur plus bas. Je ne vois aucun de mes empreintes. Si je commente le gros de la procédure stockée:
CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS
print 'before raiserror'
raiserror('this is a raised error', 18, 1)
print 'before return'
return -1
print 'after return'
/*
[snip]
*/
Ensuite, je ne reçois pas mon erreur et je vois les résultats:
before raiserror
Server: Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 5
this is a raised error
before return
La question est donc: comment puis-je sortir d'une procédure stockée dans SQL Server?
Vous pouvez utiliser RETURN
pour arrêter immédiatement l'exécution d'une procédure stockée. Citation tirée de documentation en ligne :
Quitte sans condition une requête ou une procédure. RETURN est immédiat et complet et peut être utilisé à tout moment pour sortir d'un bloc de procédure, de lot ou d'instruction. Les instructions qui suivent RETURN ne sont pas exécutées.
Hors de paranoïa, j'ai essayé votre exemple et il sort les PRINT et arrête l'exécution immédiatement.
Sauf si vous spécifiez une gravité de 20 ou plus, raiserror
n'arrêtera pas l'exécution. Voir le documentation MSDN .
La solution de contournement normale consiste à inclure un return
après chaque raiserror
:
if @whoops = 1
begin
raiserror('Whoops!', 18, 1)
return -1
end
Mettez-le dans un TRY/CATCH
.
Lorsque RAISERROR est exécuté avec une gravité supérieure ou égale à 11 dans un bloc TRY, il transfère le contrôle au bloc CATCH associé.
Référence: MSDN .
EDIT: Cela fonctionne pour MSSQL 2005+, mais je vois que vous venez de préciser que vous travaillez sur MSSQL 2000. Je vais laisser cela ici pour référence.
j'ai compris pourquoi RETURN
ne retourne pas inconditionnellement de la procédure stockée. L'erreur que je vois est pendant que la procédure stockée est en cours d'exécution compilée - pas lors de son exécution.
Considérons une procédure stockée imaginaire:
CREATE PROCEDURE dbo.foo AS
INSERT INTO ExistingTable
EXECUTE LinkedServer.Database.dbo.SomeProcedure
Même si cette procédure stord contient une erreur (c'est peut-être parce que les objets ont un nombre différent de colonnes, peut-être qu'il y a une colonne timestamp dans la table, peut-être que la procédure stockée n'existe pas), vous pouvez toujours enregistrez le. Vous pouvez le sauvegarder car vous référencez un serveur lié.
Mais lorsque vous exécutez la procédure stockée, SQL Server le compile et génère un plan de requête.
Mon erreur ne se produit pas à la ligne 114, elle est à ligne 114 SQL Server ne peut pas compiler la procédure stockée, c’est pourquoi elle échoue.
Et c'est pourquoi RETURN
ne revient pas, car il n'a pas encore commencé.
Cela fonctionne ici.
ALTER PROCEDURE dbo.Archive_Session
@SessionGUID int
AS
BEGIN
SET NOCOUNT ON
PRINT 'before raiserror'
RAISERROR('this is a raised error', 18, 1)
IF @@Error != 0
RETURN
PRINT 'before return'
RETURN -1
PRINT 'after return'
END
go
EXECUTE dbo.Archive_Session @SessionGUID = 1
Résultats
before raiserror
Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 7
this is a raised error
Cela ressemble à beaucoup de code mais la meilleure façon que j'ai trouvée de le faire.
ALTER PROCEDURE Procedure
AS
BEGIN TRY
EXEC AnotherProcedure
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
RETURN --this forces it out
END CATCH
--Stuff here that you do not want to execute if the above failed.
END --end procedure
C'est parce que vous n'avez pas d'instructions BEGIN
et END
. Vous ne devriez pas voir les empreintes ou les erreurs d’exécution de cette instruction, mais seulement Statement Completed
(ou quelque chose comme ça).