web-dev-qa-db-ja.com

SQL Server 2000:ストアドプロシージャを終了する方法

ストアドプロシージャの途中で終了するにはどうすればよいですか?

早期に(デバッグを試みながら)救済したいストアドプロシージャがあります。 RETURNRAISERRORを呼び出してみましたが、spは実行を続けます。

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]

さらに下のエラーが発生したため、実行し続けます。 printsのいずれも表示されません。ストアドプロシージャの大部分をコメントアウトした場合:

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]
   */

その後、エラーが発生せず、結果が表示されます。

before raiserror
Server: Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 5
this is a raised error
before return

質問は次のとおりです。SQLServerのストアドプロシージャをどのように救済するのですか?

60
Ian Boyd

RETURNを使用して、ストアドプロシージャの実行をすぐに停止できます。 Books Online からの引用:

クエリまたはプロシージャから無条件に終了します。 RETURNは即時かつ完全であり、プロシージャ、バッチ、またはステートメントブロックを終了するためにいつでも使用できます。 RETURNに続くステートメントは実行されません。

妄想から、私はあなたの例を試してみましたが、PRINTを出力し、すぐに実行を停止します。

80
AdaTheDev

20以上の重大度を指定しない限り、raiserrorは実行を停止しません。 MSDNドキュメント を参照してください。

通常の回避策は、すべてのreturnの後にraiserrorを含めることです。

if @whoops = 1
    begin
    raiserror('Whoops!', 18, 1)
    return -1
    end
28
Andomar

TRY/CATCH

TISブロックでRAISERRORを重大度11以上で実行すると、関連するCATCHブロックに制御が移ります

参照: [〜#〜] msdn [〜#〜]

EDIT:これはMSSQL 2005+で機能しますが、MSSQL 2000で作業していることを明確にしたことがわかります。参照。

10

RETURNがストアドプロシージャから無条件に返されない理由を理解しました。私が見ているエラーは、ストアドプロシージャが実行されているときではなく、コンパイル済みであるときに発生します。

架空のストアドプロシージャを考えます。

CREATE PROCEDURE dbo.foo AS

INSERT INTO ExistingTable
EXECUTE LinkedServer.Database.dbo.SomeProcedure

このstordプロシージャにエラーが含まれている場合でも(オブジェクトの列数が異なるため、テーブルにタイムスタンプ列がある場合、ストアドプロシージャが存在しない場合など)、引き続きsaveそれ。リンクサーバーを参照しているため、保存できます。

ただし、ストアドプロシージャを実際にexecuteすると、SQL Serverはcompilesit 、クエリプランを生成します。

私のエラーは114行目ではhappeningではなく、114行目ではonです。SQL Serverはストアドプロシージャをコンパイルできないため、失敗します。

そして、それがRETURNが返されない理由です。startedでさえないためです。

9
Ian Boyd

これはここで機能します。

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

返却値

before raiserror
Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 7
this is a raised error
4
Damir Sudarevic

これは多くのコードのように思えますが、私が見つけた最良の方法です。

    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
4
JDPeckham

BEGINおよびENDステートメントがないためです。このステートメントの実行中に印刷物やエラーが表示されることはないはずです。Statement Completed(またはそのようなもの)。

1
cjk