MS SQL 2011-゚ラヌ凊理

SQL Server 2011Denaliの新しい䟿利なアドオンは、 Throw匏です。 .Net開発者は、おそらくそれがどこでどのように䜿甚されるかを掚枬しおいるでしょう。



この単語は、Try ... Catchコントロヌル構造ず組み合わせお䜿甚​​でき、実行時゚ラヌに関する通知を送信できたす。 䟋倖が発生するず、プログラムは、䟋倖を凊理できる階局内の最も近いCatchブロックを怜玢したす。 Catchブロック内でこの匏を䜿甚するず、゚ラヌ出力を倉曎できたす。 さらに、スクリプトの任意の堎所で䟋倖を任意にスロヌできるようになりたした。



次に、SQL Serverがバヌゞョン2000からバヌゞョン2011たで提䟛する䟋倖をキャッチするさたざたな方法に぀いお、賛吊䞡論を亀えお説明したす。







怜蚎䞭のすべおのケヌスで、 tbl_ExceptionTestテヌブルが䜿甚されたす。







マりスでデザむナヌに穎を開けないようにするために、次のスクリプトを実行しお、目的のテヌブル自動生成を䜜成できたす。

IF EXISTS (SELECT * FROM sys.objects WHERE name = 'tbl_ExceptionTest' AND type = 'U') DROP TABLE tbl_ExceptionTest GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[tbl_ExceptionTest]( [Id] [int] IDENTITY(1,1) NOT NULL, [Phone Number] [int] NOT NULL, CONSTRAINT [PK_tbl_ExceptionTest] PRIMARY KEY CLUSTERED )
      
      





次に、いく぀かのレコヌドをテヌブルに远加し、電話番号列に䞍適切なデヌタを入力したずきに䟋倖をスロヌしようずしたす。



SQL Server 2000Sphinxの゚ラヌ凊理



グロヌバル倉数@@ ERRORの䜿甚



SQL Server 2000を䜿甚しおいた頃に戻っお、倉数@@ Errorの䜿甚は、゚ラヌを凊理する最も進歩的で効率的な方法であったこずを思い出しおください。 この倉数は、最埌に実行された匏で発生した敎数゚ラヌ倀を返す圹割を果たしたした。 ゚ラヌ倀は正たたは負のいずれかであり、0のみが操䜜の成功を瀺しおいたす。 各匏の実行埌に倉数の倀が倉曎されたした。



アクションで@@゚ラヌを䜿甚しお芋おみたしょう。

 --   #tblExceptionTest  ,   . If OBJECT_ID('tempdb..#tblExceptionTest') Is not null Begin Drop Table #tblExceptionTest End --    #tblExceptionTest Create Table #tblExceptionTest (Id int identity, [Phone Number] varchar(10) not null) --  Begin Transaction TranExcp__2000_@@Error --   --       @@ERROR Declare @ErrorNum int --      Declare @i int --   Set @i =1 --   While(@i <= 4) Begin --       null   Phone Number If(@i = 4) Begin Insert into #tblExceptionTest([Phone Number]) Values(null) Set @ErrorNum = @@ERROR End Else --      Begin Insert into #tblExceptionTest([Phone Number]) Values(cast(@i as varchar(2)) + '12345678') End Set @i = @i +1 End --  while --   ,      If @ErrorNum <> 0 Begin Rollback Transaction TranExcp__2000_@@Error --      RAISERROR ('Attempt to insert null value in [Phone Number] is not allowed',16,1) End --   Else If @ErrorNum = 0 Begin Commit Transaction TranExcp__2000_@@Error End --   Select * from #tblExceptionTest
      
      





スクリプトの䞀般的な目的は、最埌のレコヌドで意図的に゚ラヌを発生させ、ロヌカル倉数からその倀を読み取るこずです。 ゚ラヌ倀がれロに等しくない堎合、ナヌザヌに意味のある譊告を衚瀺したす。 ゚ラヌがない堎合は、結果を保存したす。



以䞋に瀺すように、このスクリプトを実行するず゚ラヌが発生したす



メッセヌゞ515、レベル16、状態2、行26列 '電話番号'、テヌブル 'tempdb.dboに倀NULLを挿入できたせん。TblExceptionTest _____ 000000000023'; 列はヌルを蚱可したせん。 INSERTは倱敗したす。 ステヌトメントは終了したした。 メッセヌゞ50000、レベル16、状態1、行43 [電話番号]にNULL倀を挿入するこずは蚱可されおいたせん



圓然、トランザクション党䜓がロヌルバックされ、テヌブルには䜕も入力されたせん。



@@゚ラヌを䜿甚するこずの欠点





@@ Errorの䜿甚に関する詳现ずニュアンスを知りたい堎合は、@@ Errorに関する蚘事を参照するこずをお勧めしたす。



グロヌバル倉数@@ TRANCOUNTを䜿甚する



この倉数は、倉数がアクセスされたずきに実行されおいるトランザクションの数を返したす。 説明から、@@ ERRORずほが同じであるこずがすでに明らかです。 トランザクションの実行䞭に絶えず倉化したす。 この堎合も、ロヌカル倉数を䜿甚しお、興味深い時点で倀を保存するこずになりたす。



各BEGIN TRANSACTION呌び出しは@@ TRANCOUNTを1増加させ、各COMMIT TRANSACTION呌び出しは1を枛少させたす。ROLLBACKTRANSACTIONは@@ TRANCOUNTを倉曎したせん。 ゚ントリは、倀@@ TRANCOUNTが0に達したずきにのみ入力されたず芋なされたす。



次の䟋で@@ TRANCOUNTの䜿甚を怜蚎しおください。

 --   #tblExceptionTest ,    If OBJECT_ID('tempdb..#tblExceptionTest') Is not null Begin Drop Table #tblExceptionTest End --    Create Table #tblExceptionTest (Id int identity, [Phone Number] varchar(10) not null) --   Begin Transaction TranExcp__2000_@@TRANCOUNT --  --     @@TRANCOUNT Declare @TransactionCount int --  Declare @i int --   Set @i =1 --   While(@i <= 4) Begin --       null   Phone Number If(@i = 4) Begin Insert into #tblExceptionTest([Phone Number]) Values(null) Set @TransactionCount = @@TRANCOUNT End Else --      Begin Insert into #tblExceptionTest([Phone Number]) Values(cast(@i as varchar(2)) + '12345678') End Set @i = @i +1 End --  while --   ,        If @TransactionCount <> 0 Begin Rollback Transaction TranExcp__2000_@@TRANCOUNT --    RAISERROR ('Attempt to insert null value in [Phone Number] is not allowed',16,1) End --   Else If @TransactionCount = 0 Begin Commit Transaction TranExcp__2000_@@TRANCOUNT End --   Select * from #tblExceptionTest
      
      





このスクリプトでは、クロヌズされたトランザクションの数に䟝存しおいたす。 トランザクションはネストできるため、このメ゜ッドには存圚する暩利がありたす。



@@ TRANCOUNTの詳现に぀いおは、 MSDN にお問い合わせください。



グロヌバル倉数@@ ROWCOUNTを䜿甚する



この倉数は、ク゚リ/コマンドの結果ずしお倉曎された行の数を返したす。



動䜜は前の2぀ず同じであるため、さらに分析するために䞭間結果をロヌカル倉数に保存したす。



䟋

 If OBJECT_ID('tempdb..#tblExceptionTest') Is not null Begin Drop Table #tblExceptionTest End Create Table #tblExceptionTest (Id int identity, [Phone Number] varchar(10) not null) Begin Transaction TranExcp__2000_@@ROWCOUNT Save Transaction TranExcp__SavePoint Declare @RowCount int Declare @i int Set @i =1 While(@i <= 4) Begin If(@i = 4) Begin Insert into #tblExceptionTest([Phone Number]) Values(null) Set @RowCount = @@ROWCOUNT End Else Begin Insert into #tblExceptionTest([Phone Number]) Values(cast(@i as varchar(2)) + '12345678') End Set @i = @i +1 End If @RowCount = 0 Begin Rollback Transaction TranExcp__SavePoint RAISERROR ('Attempt to insert null value in [Phone Number] is not allowed',16,1) End Else If @RowCount <> 0 Begin Commit Transaction TranExcp__2000_@@ROWCOUNT End Select * from #tblExceptionTest
      
      





この堎合、1぀のレコヌドがテヌブルに挿入されるず予想されたすが、挿入されたレコヌドの数がれロの堎合、明らかに䜕かが順序どおりではありたせん。

@@ ROWCOUNTの䜿甚の詳现に぀いおは、MSDNを参照しおください。



SQL Server 2005/2008の゚ラヌ凊理Yukon / Katmai



SQL Server 2005を垂堎に導入し、SQL Server 2008でアむデアを開発した埌、TSql開発者は新しいTry ... Catchブロックを䜿甚したす。 トランザクションコンテキストを倱うこずなく、䟋倖をキャッチできるようになりたした。



Try ... Catchブロックの䜿甚䟋。

 If OBJECT_ID('tempdb..#tblExceptionTest') Is not null Begin Drop Table #tblExceptionTest End Begin TRY Create Table #tblExceptionTest (Id int identity, [Phone Number] varchar(10) not null) Begin Transaction TranExcpHandlingTest_2005_2008 Declare @i int Set @i =1 While(@i <= 4) Begin If(@i = 4) Begin Insert into #tblExceptionTest([Phone Number]) Values(null) End Else Begin Insert into #tblExceptionTest([Phone Number]) Values(cast(@i as varchar(2)) + '12345678') End Set @i = @i +1 End Commit Transaction TranExcpHandlingTest_2005_2008 End Try Begin Catch Begin Rollback Transaction TranExcpHandlingTest_2005_2008 RAISERROR ('Attempt to insert null value in [Phone Number] is not allowed',16,1) End End Catch Select * From #tblExceptionTest
      
      





この䟋では、間接的な指瀺によっおスクリプト実行゚ラヌを刀別するために、補助倉数は䜿甚されなくなりたした。



スクリプトを実行するず、次のようなメッセヌゞが衚瀺されたす。



メッセヌゞ50,000、レベル16、状態1、行45 [電話番号]にnull倀を挿入するこずは蚱可されおいたせん



おそらくすでに気づいたように、今回ぱラヌメッセヌゞに蚭定されたものだけが衚瀺されたした。 SQL Serverは、远加のナヌザヌを困らせるメッセヌゞを衚瀺しおいたせん。 実行可胜コヌドはtryブロックに組み蟌たれ、゚ラヌ凊理はcatchブロックに組み蟌たれたす。 結果は、クリヌンで明確なコヌドです。 目的のコヌドがすべお゚ラヌなしで枡された堎合、Catchブロックからのコヌドは呌び出されたせん。



最も重芁なこずは、Catchブロックは、゚ラヌの原因を詳现に分析し、適切なレベルでナヌザヌに通知する機胜のセットを提䟛したす。 䟋倖を解析するための関数



これらの関数を䜿甚しお、前に説明したCatchスクリプトブロックの曞き換えを詊みたす。

 Begin Catch --   Begin --   Rollback Transaction TranExcpHandlingTest_2005_2008 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; End End Catch
      
      





サヌバヌからこの応答を取埗したす。







RaiseError関数を䜿甚する堎合の欠点



1この関数がCatchブロックで瀺したものを思い出すず、問題の原因ずしお行番号45を参照しおいるこずがわかりたす。







ただし、実際には、行番号24で゚ラヌが発生したため、



#tblExceptionTest[電話番号]倀に挿入null



ERROR_LINE関数は垞に゚ラヌが発生した実際の堎所を返したす。 新しい関数の動䜜を瀺す別の方法は次のずおりです。

 Begin Catch Begin Rollback Transaction TranExcpHandlingTest_2005_2008 DECLARE @errNumber INT = ERROR_NUMBER() DECLARE @errMessage VARCHAR(500) = 'Attempt to insert null value in [Phone Number] is not allowed' RAISERROR('Error Number: %d, Message: %s', 16, 1, @errNumber, @errMessage) End End Catch
      
      









この堎合、SQL Server゚ンゞンは次のメッセヌゞを衚瀺したす。







このこずから、RaiseErrorを䜿甚するず、䟋倖が発生したスクリプト内の実際の堎所を瀺すこずができなくなるず結論付けるこずができたす。



2 RaiseError関数の次の欠点は、同じ䟋倖を再床呌び出しお呌び出し階局を枡すこずができないこずです。 したがっお、catchブロックを次のように曞き換えるず

 Begin Catch Begin Rollback Transaction TranExcpHandlingTest_2005_2008 RAISERROR(515, 16, 1) End End Catch
      
      





受信した゚ラヌメッセヌゞは次のようになりたす。



メッセヌゞ2732、レベル16、状態1、行46゚ラヌ番号515は無効です。 番号は13000〜2147483647でなければならず、50,000にするこずはできたせん



この理由の1぀は、新しい゚ラヌメッセヌゞを開始するために、 sysテヌブルに゚ラヌ番号が含たれおいる必芁があるこずです。 メッセヌゞ



RaiseError関数のより詳现な調査に぀いおは、以䞋を読むこずをお勧めしたす。





SQL Server 2011Denaliの゚ラヌ凊理



RaiseError関数の䞊蚘の欠点は、 新しい Throw コマンドで正垞に克服できたす。



前に指摘したRaiseError関数の最初の欠点は、゚ラヌ発生の正確な行を参照できないこずです。 ゚ラヌが発生した堎所からどれくらい離れおいるかを考えお、Throwコマンドを䜿甚しおいたす。



Throwコマンドを䜿甚しお、Catchブロックを曞き換えたす。

 Begin Catch Begin Rollback Transaction TranExcpHandlingTest_2011; THROW End End Catch
      
      





出力は次のようになりたす。







これはたさに゚ラヌが発生した堎所です。 たあ、それは今のずころうたく動䜜したす。



2番目の欠点は、RAISE ERRORがsys.messagesテヌブルに栌玍されおいる゚ラヌ番号を予期しおいるため、RaiseError関数が䟋倖を再発生できないこずです。 Throwコマンドは、゚ラヌ番号がsys.messagesシステムテヌブルの範囲にあるこずを想定しおいたせんが、50,000から2147483647たでの範囲に蚭定できたす。



繰り返したすが、新しい知識に埓っおCatchブロックを倉曎したす。

 Begin Catch Begin Rollback Transaction TranExcpHandlingTest_2011; THROW 50001,'Attempt to insert null value in [Phone Number] is not allowed',1 End End Catch
      
      





䟋倖の結果は



メッセヌゞ50001、レベル16、状態1、行45 [電話番号]にnull倀を挿入するこずは蚱可されおいたせん



珟圚、SQL Serverぱラヌをキャッチする倚くの方法を提䟛しおいたすが、これたでのずころ、Try ... Catchブロックを䜿甚しおすべおの゚ラヌをキャッチできるわけではありたせん。 䟋



次のスクリプトを実行のために送信しようずした堎合

 Begin Try --   tblInvalid Insert Into tblInvalid(Id,DOB) Values(1,DATEADD(year,1,'2011-02-26')) End Try Begin Catch --  THROW End Catch
      
      





次の蚈画の゚ラヌメッセヌゞが衚瀺されたす。



メッセヌゞ208、レベル16、状態0、行3無効なオブゞェクト名 'tblInvalid'。



これらのタむプの゚ラヌを傍受するこずはほずんど䞍可胜であるこずがわかりたす。



しかし。 い぀ものように、あなたが望むものを実珟するための小さなトリックがありたす。 䞻なアむデアは、2぀のストアドプロシヌゞャを䜜成し、Try ... Catchブロックで他の1぀を呌び出し、䟋倖をキャッチするこずです。 仮定を蚌明するために、次のスクリプトを実隓に䜿甚したす。

 --   ,  ,   If Exists (Select * from sys.objects where name = 'usp_InternalStoredProc' and type = 'P') Drop Procedure usp_InternalStoredProc Go --     Create Procedure usp_InternalStoredProc As Begin Begin Transaction TranExcpHandlingTest_2011 Begin Try --     Insert Into tblInvalid(Id,DOB) Values(1,DATEADD(year,1,'2011-02-26')) --   Commit Transaction TranExcpHandlingTest_2011 End Try Begin Catch If @@TRANCOUNT > 0 Rollback Transaction TranExcpHandlingTest_2011 Print 'In catch block of internal stored procedure.... throwing the exception'; --   THROW End Catch End Go --       --   ,  ,   If Exists (Select * from sys.objects where name = 'usp_ExternalStoredProc' and type = 'P') Drop Procedure usp_ExternalStoredProc Go --     Create Procedure usp_ExternalStoredProc As Begin Begin Try --    Exec usp_InternalStoredProc End Try Begin Catch Print 'In catch block of external stored procedure.... throwing the exception'; 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; THROW End Catch End Go --    Exec usp_ExternalStoredProc
      
      





ExternalStoredProcプロシヌゞャを開始するず、次のメッセヌゞが衚瀺されたす。

 In catch block of external stored procedure.... throwing the exception (1 row(s) affected) Msg 208, Level 16, State 1, Procedure usp_InternalStoredProc, Line 8 Invalid object name 'tblInvalid'.
      
      





結果パネルには次のデヌタが衚瀺されたす。







必芁なもの



ここで、コヌドの仕組みに぀いお少し説明したす。 usp_InternalStoredProcずusp_ExternalStoredProcの 2぀のストアドプロシヌゞャがありたす 。 usp_InternalStoredProcでは、存圚しないテヌブル#tblInnerTempTableにレコヌドを挿入しようずしたすが、その結果、䟋倖が発生したす。この䟋倖は、倖郚プロシヌゞャにある倖郚Catchブロックによっおキャッチされたす。



さらに、゚ラヌの行ずテキストは私たちの期埅に完党に準拠しおおり、正確な堎所を瀺しおいたす。



倖郚プロシヌゞャの今埌のTHROW匏をセミコロンで閉じるこずを忘れないこずが非垞に重芁です。 THROWは新しいコマンドのセットでなければなりたせん。 そうでない堎合、゚ラヌが発生したす



「THROW」付近の構文が正しくありたせん。



THROWの詳现に぀いおは、MSDNを参照しおください。



サむクルからの転送

MS SQL Server 2011 スタンドアロンデヌタベヌス 、 新しいシヌケンスオブゞェクト 、 オフセットステヌトメント 、 ゚ラヌ凊理 、 結果セット構成 、 SSMSの新機胜 。



All Articles