web-dev-qa-db-ja.com

SQLストアドプロシージャにTry / Catchを追加する方法

CREATE PROCEDURE [dbo].[PL_GEN_PROVN_NO1]        
@GAD_COMP_CODE  VARCHAR(2) =NULL, 
@@voucher_no numeric =null output 
AS         
BEGIN  
    DECLARE @NUM NUMERIC 
    DECLARE @PNO  NUMERIC                               
    SET @PNO = 0 
    DECLARE @PNO1 NUMERIC
    SET @PNO1=0 

--  begin transaction 

    IF NOT EXISTS (select GLDC_NEXT_PRV_NO
               FROM   GLAS_FINANCIAL_DOCUMENTS          
                   WHERE  GLDC_COMP_CODE  = @GAD_COMP_CODE        
                   AND GLDC_DOC_CODE  = 'JV' )
    BEGIN
               RAISERROR ('Error in generating provision number..',16,1) 
               -- ROLLBACK TRANSACTION
    END
ELSE
SELECT @PNO=ISNULL(GLDC_NEXT_PRV_NO,0)+1
FROM   GLAS_FINANCIAL_DOCUMENTS          
WHERE  GLDC_COMP_CODE  = @GAD_COMP_CODE        
AND GLDC_DOC_CODE  = 'JV' 

UPDATE  GLAS_FINANCIAL_DOCUMENTS        
SET GLDC_NEXT_PRV_NO = @PNO         
WHERE  GLDC_COMP_CODE  = @GAD_COMP_CODE        
AND GLDC_DOC_CODE  = 'JV' 

set @@VOUCHER_NO=@PNO    
--commit transaction 
END

このプロシージャでは、例外のキャッチをどのように処理できますか?

36
Domnic

TRY ... CATCH(Transact-SQL) を参照してください

 CREATE PROCEDURE [dbo].[PL_GEN_PROVN_NO1]        
       @GAD_COMP_CODE  VARCHAR(2) =NULL, 
       @@voucher_no numeric =null output 
       AS         
   BEGIN  

     begin try 
         -- your proc code
     end try

     begin catch
          -- what you want to do in catch
     end catch    
  END -- proc end
40
Preet Sangha

Transact-SQLは、トランザクションの複雑さが増すため、C#またはC++のtry/catchブロックよりも少し注意が必要です。 CATCHブロックはxact_state()関数を確認し、コミットできるかロールバックする必要があるかを判断する必要があります。ブログでトピックを取り上げましたが、可能性のあるネストされたトランザクションを含むtry catchブロックでトランザクションを正しく処理する方法を示す記事があります。 例外処理とネストされたトランザクション

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(),
                 @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
        return;
    end catch   
end
31
Remus Rusanu

SQLストアドプロシージャを使用したエラー処理

TRY/CATCH エラー処理は、プロシージャ内またはプロシージャ外(あるいはその両方)で実行できます。以下の例は、両方の場合のエラー処理を示しています。

さらに実験したい場合は、 クエリの分岐 Stack Exchangeで Data Explorer を使用できます。

(これは 一時ストアドプロシージャ ...を使用します--通常 SPはSEDEで作成できませんが、機能は同じです。)

_--our Stored Procedure
create procedure #myProc as --we can only create #temporary stored procedures on SEDE. 
  begin
    BEGIN TRY
      print 'This is our Stored Procedure.'
      print 1/0                          --<-- generate a "Divide By Zero" error.
      print 'We are not going to make it to this line.'
    END TRY

    BEGIN CATCH
      print 'This is the CATCH block within our Stored Procedure:'
          + ' Error Line #'+convert(varchar,ERROR_LINE())
          + ' of procedure '+isnull(ERROR_PROCEDURE(),'(Main)')
      --print 1/0                        --<-- generate another "Divide By Zero" error.
        -- uncomment the line above to cause error within the CATCH ¹ 
    END CATCH
  end
go

--our MAIN code block:
BEGIN TRY
  print 'This is our MAIN Procedure.'
  execute #myProc  --execute the Stored Procedure
      --print 1/0                        --<-- generate another "Divide By Zero" error.
        -- uncomment the line above to cause error within the MAIN Procedure ²
  print 'Now our MAIN sql code block continues.'
END TRY

BEGIN CATCH
  print 'This is the CATCH block for our MAIN sql code block:'
          + ' Error Line #'+convert(varchar,ERROR_LINE())
          + ' of procedure '+isnull(ERROR_PROCEDURE(),'(Main)')
END CATCH
_

上記のsqlをそのまま実行した結果は次のとおりです。

_This is our MAIN Procedure.
This is our Stored Procedure.
This is the CATCH block within our Stored Procedure: Error Line #5 of procedure #myProc
Now our MAIN sql code block continues.
_

¹ストアドプロシージャ[〜#〜] catch [〜#〜]ブロックから「追加のエラー行」のコメントを外すと、 :

_This is our MAIN procedure.
This is our Stored Procedure.
This is the CATCH block within our Stored Procedure: Error Line #5 of procedure #myProc
This is the CATCH block for our MAIN sql code block: Error Line #13 of procedure #myProc
_

²[〜#〜] main [〜#〜]プロシージャから「追加のエラー行」のコメントを外すと、以下が生成されます。

_This is our MAIN Procedure.
This is our Stored Pprocedure.
This is the CATCH block within our Stored Procedure: Error Line #5 of procedure #myProc
This is the CATCH block for our MAIN sql code block: Error Line #4 of procedure (Main)
_

エラー処理に単一の手順を使用する

ストアドプロシージャとエラー処理のトピックについては、単一の動的なストアドプロシージャを使用して、他の複数のプロシージャまたはコードセクションのエラーを処理すると役立ちます(より整頓されています)。

例を次に示します:

_--our error handling procedure
create procedure #myErrorHandling as
  begin
    print ' Error #'+convert(varchar,ERROR_NUMBER())+': '+ERROR_MESSAGE()  
    print ' occurred on line #'+convert(varchar,ERROR_LINE())
         +' of procedure '+isnull(ERROR_PROCEDURE(),'(Main)')
    if ERROR_PROCEDURE() is null       --check if error was in MAIN Procedure
      print '*Execution cannot continue after an error in the MAIN Procedure.'
  end
go

create procedure #myProc as     --our test Stored Procedure
  begin
    BEGIN TRY
      print 'This is our Stored Procedure.'
      print 1/0                       --generate a "Divide By Zero" error.
      print 'We will not make it to this line.'
    END TRY
    BEGIN CATCH
     execute #myErrorHandling
    END CATCH
  end
go

BEGIN TRY                       --our MAIN Procedure
  print 'This is our MAIN Procedure.'
  execute #myProc                     --execute the Stored Procedure
  print '*The error halted the procedure, but our MAIN code can continue.'
  print 1/0                           --generate another "Divide By Zero" error.
  print 'We will not make it to this line.'
END TRY
BEGIN CATCH
  execute #myErrorHandling
END CATCH
_

出力例: (このクエリはSEDEで分岐できます here 。)

_This is our MAIN procedure.
This is our stored procedure.
 Error #8134: Divide by zero error encountered.
 occurred on line #5 of procedure #myProc
*The error halted the procedure, but our MAIN code can continue.
 Error #8134: Divide by zero error encountered.
 occurred on line #5 of procedure (Main)
*Execution cannot continue after an error in the MAIN procedure.
_

ドキュメンテーション:

TRY/CATCH ブロックのスコープでは、次のシステム関数を使用して、CATCHブロックを引き起こしたエラーに関する情報を取得できます。実行される:

  • ERROR_NUMBER() はエラーの数を返します。
  • ERROR_SEVERITY() は重大度を返します。
  • ERROR_STATE() は、エラー状態番号を返します。
  • ERROR_PROCEDURE() は、エラーが発生したストアドプロシージャまたはトリガーの名前を返します。
  • ERROR_LINE() は、エラーの原因となったルーチン内の行番号を返します。
  • ERROR_MESSAGE() は、エラーメッセージの完全なテキストを返します。テキストには、長さ、オブジェクト名、時間など、置換可能なパラメーターに指定された値が含まれます。

ソース

SQLエラーには2つのタイプがあることに注意してください:TerminalおよびCatchableTRY/CATCHは[明らかに]「キャッチ可能な」エラーのみをキャッチします。これは、SQLエラーについて詳しく知るための多くの方法の1つですが、おそらく最も有用です。

Homerが言うようにので、「今は失敗する方が良い」(開発中)と比較して。 。 。

12
ashleedawg

うん-try catchステートメントを次のようにネストすることもできます:

BEGIN TRY
SET @myFixDte = CONVERT(datetime, @myFixDteStr,101)
END TRY
BEGIN CATCH
    BEGIN TRY
        SET @myFixDte = CONVERT(datetime, @myFixDteStr,103)
END TRY
BEGIN CATCH
    BEGIN TRY
        SET @myFixDte = CONVERT(datetime, @myFixDteStr,104)
    END TRY
    BEGIN CATCH
        SET @myFixDte = CONVERT(datetime, @myFixDteStr,105)
    END CATCH
END CATCH END CATCH
3
Chagbert
Create Proc[usp_mquestions]  
( 
 @title  nvarchar(500),   --0
 @tags  nvarchar(max),   --1
 @category  nvarchar(200),   --2
 @ispoll  char(1),   --3
 @descriptions  nvarchar(max),   --4
)              
 AS  
 BEGIN TRY




BEGIN
DECLARE @message varchar(1000); 
DECLARE @tempid bigint; 

IF((SELECT count(id) from  [xyz] WHERE title=@title)>0)
BEGIN
SELECT 'record already existed.';
END
ELSE
BEGIN               


if @id=0 
begin 
select @tempid =id from [xyz] where id=@id;

if @tempid is null 
BEGIN 
        INSERT INTO xyz
        (entrydate,updatedate)
        VALUES
        (GETDATE(),GETDATE())

        SET @tempid=@@IDENTITY;
 END 
END 
ELSE 
BEGIN 
set @tempid=@id 
END 
if @tempid>0 
BEGIN 

    -- Updation of table begin--


UPDATE  tab_questions
set title=@title, --0 
 tags=@tags, --1 
 category=@category, --2 
 ispoll=@ispoll, --3 
 descriptions=@descriptions, --4 
 status=@status, --5

WHERE id=@tempid ; --9 ;


IF @id=0 
BEGIN 
SET @message= 'success:Record added successfully:'+ convert(varchar(10), @tempid)
END 
ELSE 
BEGIN 
SET @message= 'success:Record updated successfully.:'+ convert(varchar(10), @tempid)

END 
END 
ELSE 
BEGIN 
SET @message= 'failed:invalid request:'+convert(varchar(10), @tempid)
END 

END
END

END TRY
BEGIN CATCH
    SET @message='failed:'+ ERROR_MESSAGE();
END CATCH
SELECT @message;
0
Harikesh Yadav