web-dev-qa-db-ja.com

SQL Server T-SQLエラー処理のベストプラクティスの使用方法は何ですか?

主にSQL Server 7.0で記述された大規模なアプリケーションがあり、すべてのデータベース呼び出しはストアドプロシージャに対して行われます。 現在、より多くのT-SQL機能を提供するSQL Server 2005を実行しています。

ほぼすべてのSELECT、INSERT、UPDATE、およびDELETEの後、@@ ROWCOUNTおよび@@ ERRORがローカル変数にキャプチャされ、問題が評価されます。問題がある場合、次のことが行われます。

  • エラーメッセージ出力パラメーターが設定されています
  • ロールバック(必要な場合)が行われます
  • ログテーブルに情報が書き込まれます(INSERT)
  • この手順に固有のエラー番号を返します(致命的な場合は正、警告は警告)

それらはすべて行をチェックせず(既知の場合のみ)、ログ/デバッグ情報が多少異なります。また、行ロジックはエラーロジックから分割されています(WHERE句で同時実行フィールドがチェックされる更新では、rows = 0は他の誰かがデータを更新したことを意味します)。ただし、かなり一般的な例を次に示します。

SELECT, INSERT, UPDATE, or DELETE

SELECT @Error=@@ERROR, @Rows=@@ROWCOUNT
IF @Rows!=1 OR @Error!=0
BEGIN
    SET @ErrorMsg='ERROR 20, ' + ISNULL(OBJECT_NAME(@@PROCID), 'unknown') 
                               + ' - unable to ???????? the ????.'
    IF @@TRANCOUNT >0
    BEGIN 
        ROLLBACK
    END

    SET @LogInfo=ISNULL(@LogInfo,'')+'; '+ISNULL(@ErrorMsg,'')+
        + ' @YYYYY='        +dbo.FormatString(@YYYYY)
        +', @XXXXX='        +dbo.FormatString(@XXXXX)
        +', Error='         +dbo.FormatString(@Error)
        +', Rows='          +dbo.FormatString(@Rows)

    INSERT INTO MyLogTable (...,Message) VALUES (....,@LogInfo)

    RETURN 20

END

これをTRY-CATCH T-SQLに置き換える方法を検討しています。 TRY ... CATCH(Transact-SQL) 構文について読んだことがあるので、単に要約を投稿するだけではありません。エラー処理方法を実行または改善するための良いアイデアと方法bestを探しています。 Try-Catchである必要はなく、T-SQLエラー処理の適切な使用またはベストプラクティスの使用だけです。

33
KM.

あなたはこれを読むべきです:

http://www.sommarskog.se/error-handling-I.html

そのリンクを十分に推奨することはできません。少し長いですが、良い意味で。

最初にSQL Server 2000用に作成されたという免責事項がありますが、SQL Server 2005+の新しいtry/catchエラー処理機能についても説明しています。

31
Joel Coehoorn

現在、このテンプレートは、実行するクエリに使用します(DDLステートメントなどで必要ない場合は、Transactionのものを省略できます)。

BEGIN TRANSACTION
BEGIN TRY
    // do your SQL statements here

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage

    ROLLBACK TRANSACTION
END CATCH

もちろん、キャッチした例外をエラーログテーブルに簡単に挿入できます。

それは私たちにとって本当にうまくいきます。コード生成(CodeSmithなど)またはカスタムC#コードを使用して、古いストアドプロシージャから新しい形式への変換の一部を自動化することもできます。

22
marc_s

エラー処理の具体的なベストプラクティスはありません。それはすべて、ニーズが何であり、一貫していることです。

電話番号を保存するテーブルとストアドプロシージャのサンプルを次に示します。

 SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_PADDING ON
    GO
    CREATE TABLE [dbo].[Phone](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [Phone_Type_ID] [int] NOT NULL,
        [Area_Code] [char](3) NOT NULL,
        [Exchange] [char](3) NOT NULL,
        [Number] [char](4) NOT NULL,
        [Extension] [varchar](6) NULL,
     CONSTRAINT [PK_Phone] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO
    SET ANSI_PADDING OFF
    GO
    /**/

    CREATE PROCEDURE [dbo].[usp_Phone_INS]
         @Customer_ID INT
        ,@Phone_Type_ID INT
        ,@Area_Code CHAR(3)
        ,@Exchange CHAR(3)
        ,@Number CHAR(4)
        ,@Extension VARCHAR(6)
    AS
    BEGIN
        SET NOCOUNT ON;

        DECLARE @Err INT, @Phone_ID INT

        BEGIN TRY
            INSERT INTO Phone
                (Phone_Type_ID, Area_Code, Exchange, Number, Extension)
            VALUES
                (@Phone_Type_ID, @Area_Code, @Exchange, @Number, @Extension)
            SET @Err = @@ERROR
            SET @Phone_ID = SCOPE_IDENTITY()
            /* 
                Custom error handling expected by the application.
                If Err = 0 then its good or no error, if its -1 or something else then something bad happened.
            */
            SELECT ISNULL(@Err,-1) AS Err, @Phone_ID
        END TRY
        BEGIN CATCH
            IF (XACT_STATE() <> 0)
                BEGIN
                    ROLLBACK TRANSACTION
                END

            /* 
                Add your own custom error handling here to return the passed in paramters. 
                I have removed my custom error halding code that deals with returning the passed in parameter values.
            */

            SELECT ERROR_NUMBER() AS Err, ISNULL(@Phone_ID,-1) AS ID
        END CATCH
    END
6
DBAndrew

あなたはすでにこれについて非常に良いハンドルを持っているようです。 SQLプログラマーの95%以上が世に出ていると思います。

ここで興味深い情報を見つけることができます:

[関連のない]提案:「!=」の代わりに「<>」の使用を開始します。

[* SQL Junkiesは廃止されたため、2番目の記事は利用できません。どこかに再公開して、リンクを更新しようとします。]

3
Rob Garrison