SQLServerエラー処理およびTRYCATCH
- 24-07-2022
- Toanngo92
- 0 Comments
Mục lục
導入
SQL Serverでのエラー処理は、さまざまな手法によって簡単になりました。
SQL Serverには、ユーザーがエラーをより効果的に制御するのに役立つオプションが導入されています
通常、エンドユーザーはアプリケーション側に表示されるエラーをキャッチできません。
したがって、SQL Serverは、バックエンドでのより効率的なエラー制御のためにTRY…CATCHステートメントを提供します。
一部のシステム機能は、エラーに関する関連情報を出力できるため、エラーの修正が容易になります。
エラーの種類
T-SQLプログラマーは、SQLServerステートメントを操作するときに発生するエラーの種類に注意する必要があります。最初のステップは、エラーのタイプを識別し、次にエラーの処理方法を理解することです。
エラータイプのリスト
構文エラー
コードが構文的に正しくない場合に構文エラーが発生し、SQLServerは理解できません。これらのエラーは、T-SQLブロックまたはストアドプロシージャの実行を開始する前にSQLServerによって検出されます。
有効な構文を覚えていないためにユーザーが間違ったキーワードや操作を入力すると、コードエディターがそれを指摘します。
ユーザーがキーワードの入力を忘れた場合、またはコマンドを完了するためにアクションが必要な場合、ユーザーがコマンドを実行すると、コードエディターはエラーを報告します。
構文エラー(構文エラー)は、コードエディターが示すように簡単に識別できますが、コマンドラインアプリケーションを使用している場合、エラーはユーザーがコマンドを実行した後にのみ表示されます。
実行時エラー
アプリケーションがSQLServerまたはオペレーティングシステムでサポートされていないタスクを処理しようとすると、ランタイムエラーが発生します。
発生する可能性のあるいくつかの実行時エラーは次のとおりです。
- 0による除算の計算を処理します
- 明示的に定義されていないコードを実行しようとします。 (以下の例では、値がデータ型で表すことができるよりも大きい場合があります)。
実行時エラーが発生する一般的な状況:
- 使用できない(削除された)ストアドプロシージャ、関数、またはトリガーを使用します。
- 処理できないオブジェクトまたは変数を操作するタスクを処理しようとしました(テーブルが削除され、データベースにありません…)
- アプリケーションが過負荷の場合のRAMオーバーフロー(スタックオーバーフロー)の状況
- 互換性のないデータ型のタスクを処理してみてください。
- 条件文の誤用。
エラー処理を実装する
ソフトウェア開発プロセスにおいて重要なことの1つは、エラー処理に注意を払うことです。いくつかの点で、ユーザーはデータベースを設計するときに例外の処理に注意を払う必要があります。さまざまな処理メカニズムを使用できます。
- INSERT、DELETE、UPDATeなどのDMLステートメントを実行する場合、ユーザーはエラーを処理して正しい出力を確保できます。
- トランザクションが失敗し、ユーザーがトランザクションをロールバックする必要がある場合は、適切なエラーメッセージがユーザーに表示されます。
- SQL Serverでカーソルを操作する場合、ユーザーはエラーを処理して正確な結果を保証できます。
TRY…CATCHコマンドブロック
TRY … CATCHブロックは、TransactSQLで例外処理を実装するために使用されます。 1つ以上のT-SQ1命令は、TRブロックによって制限されます。 TRYブロックでエラーが発生した場合、制御はcatchブロックに流れます。このブロックには、CATCHブロック内に1つ以上のステートメントが含まれている場合があります。
構文:
BEGIN TRY {sql_statement | statement_block} END TRY BEGIN CATCH [ {sql_statement | statement_block}] END CATCH [;]
例えば:
BEGIN TRY DECLARE @num int; SELECT @num=217/0; END TRY BEGIN CATCH PRINT 'Error occurred, unable to devide by 0' END CATCH;
エラー情報
最善の解決策は、エラー情報をエラーと一緒に表示することです。これにより、エラーを迅速かつ効率的に解決できます。
これを行うには、CATCHブロック内でシステム関数を使用して、ブロックの実行時に生成されたエラーに関する情報を見つける必要があります。
エラー情報を提供するシステム機能のリスト:
- ERROR_NUMBER():エラー番号を返します。
- ERROR_SERVERITY():重大度を返します
- ERROR_STATE():エラーステータス番号を返します。
- ERROR_PROCEDURE():エラーの原因となったトリガーまたはストアドプロシージャの名前を返します。
- ERROR_LINE():エラーの原因となった行数を返します
- ERROR_MESSAGE():エラーの完全なテキストを返します。テキストには、オブジェクト名、長さなどのパラメーターとして提供された値が含まれます。
これらの関数は、CATCHブロックの外部で呼び出された場合にNULLを返します
エラー情報とともにTRY…CATCHを使用する
USE AdventureWorks2019; GO BEGIN TRY SELECT 217/0; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumer, ERROR_SEVERITY() AS ErrorSeverity, ERROR_LINE() AS ErrorLine, ERROR_MESSAGE() AS ErrorMessage; END CATCH; GO
ストアドプロシージャの例には、エラー処理関数が含まれています。
USE AdventureWorks2019; GO IF OBJECT_ID ('sp_ErrorInfo','P') IS NOT NULL DROP PROCEDURE sp_ErrorInfo; GO CREATE PROCEDURE sp_ErrorInfo AS 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; GO BEGIN TRY SELECT 217/0 END TRY BEGIN CATCH EXEC sp_ErrorInfo; END CATCH
トランザクションでのTRY…CATCHの使用
USE AdventureWorks2019; GO BEGIN TRANSACTION; BEGIN TRY DELETE FROM Production.Product WHERE ProductID = 980; 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; IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; END CATCH; IF @@TRANCOUNT > 0 COMMIT TRANSACTION; GO
コミットできないトランザクション
TRYブロックからエラーが生成されると、エラーが有効になり、トランザクションはコミットされていないトランザクションとして扱われます。コミットできないトランザクションは、ROLLBACKTRANSACTIONまたは読み取り操作のみを実行します。
トランザクションは、トランザクションのコミットまたは書き込み操作を実行するTransact-SQLステートメントを実行しません。
@@エラー
@@ ERROR関数は、最後に実行されたT-SQLステートメントのエラー番号を返します。
構文:
@@ERROR
例えば:
USE AdventureWorks2019; GO BEGIN TRY UPDATE HumanResources.EmployeePayHistory SET PayFrequency = 4 WHERE BusinessEntityID = 1; END TRY BEGIN CATCH IF @@ERROR = 547 PRINT N'Check constraint violation has occurred.'; END CATCH
RAISERROR
RAISERRORステートメントは、セッションのエラー処理を開始し、エラーメッセージを表示します。
RAISERRORは、sys.messageカタログビューに保存されているユーザー定義メッセージを参照したり、実行時に動的エラーメッセージを作成したりできます。
構文:
RAISERROR ( {msg_id | msg_str | @local_variable} {,serverity , state} [,argument,[,...n]]) [WITH option [,...n]]
そこで:
- msg_id :sp_addmessageを使用してsys.messagesカタログビューに保存されるユーザー定義のエラーメッセージを指定します。
- msg_str :フォーマットを使用してユーザー定義のエラーメッセージを定義します。 msg_strは、変換オプションを含む文字列です。パラメータは、printf関数の文字列形式と同様にd、i、o、s、x、X、uにすることができます。
カスタムオプションの値のリスト:
価値 | 説明 |
ログ | データベースおよびアプリケーションのエラーログにエラーを記録します。 |
NOWAIT | クライアントに直接通知を送信する |
SETERROR | 重大度に関係なく、ERROR_NUMBERと@@ERRORの値をmsg_idまたは5000に割り当てます |
RAISERRORを実行すると、次のエラーが返されます。
- TRYブロックの範囲外
- TRYブロックの重大度が10以下である
- 重大度20以上、データベースの切断。
RAISERROR()を使用してカスタムエラーを出力する例:
RAISERROR (N'This is an error message %s %d',10,1,N'serial number',23); GO
TRY CATCHでRAISERRORを使用する例:
BEGIN TRY RAISERROR('Raises Error in the TRY block',16,1); 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,@ErrorSeverity,@ErrorState); END CATCH;
ERROR_SEVERITY
ERROR_SEVERITY関数は、TRYCATCH構造体のcatchブロックでエラーの重大度を返します。
この関数は、CATCHブロックの外部で呼び出された場合、nullを返します。 ERROR _SEVERITYは、CATCHブロックのスコープ内のどこからでも呼び出すことができます。
ネストされたCATCHブロックでは、ERROR_SEVERITYは、参照するcatchブロックのスコープを決定するエラーを返します。
構文:
ERROR_SEVERITY()
例えば:
BEGIN TRY SELECT 217/0; END TRY BEGIN CATCH SELECT ERROR_SEVERITY() AS ErrorSeverity; END CATCH; GO
ERROR_PROCEDURE
ERROR_PROCEDURE関数は、TRYCATCHコンストラクトのエラーが実行されたトリガーまたはストアドプロシージャの名前を返します。
構文:
ERROR_PROCEDURE()
nvarcharデータ型を返します。関数がCATCHブロックで呼び出されると、エラーが発生したストアドプロシージャの名前が返されます。
ERROR_PROCEDUREは、CATCHブロック内のどこからでも呼び出すことができます。
例えば:
USE AdventureWorks2019; GO IF OBJECT_ID ('usp_Example','P') IS NOT NULL DROP PROCEDURE usp_Example; GO CREATE PROCEDURE usp_Example AS SELECT 217/0; GO BEGIN TRY EXECUTE usp_Example; END TRY BEGIN CATCH SELECT ERROR_PROCEDURE() AS ErrorProcedure; END CATCH; GO
ERROR_NUMBER
CATCHブロックで呼び出されたERROR_NUMBER関数は、TRY>>CATCH構造体が実行されたときにCATCHブロックによって生成されたエラーの数を返します。
構文:
ERROR_NUMBER()
ERROR_NUMBERは、エラー実行の数に関係なく(異なるステートメントで複数の例外が発生した場合)、対応するエラーコードを返し、CATCHブロックのスコープ内で実行されます。これは@@ERRORとは異なり、エラーが発生するとすぐに内部エラー番号のみが返され、スコープはCATCHブロックの最初のステートメントにのみ存在します。
例えば:
BEGIN TRY SELECT 217/0; SELECT 218/0; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber; END CATCH; GO
エラーメッセージ
ERROR_MESSAGE関数は、TRYCATCH構造体の構造体で発生したエラーのテキストメッセージを返します。
構文:
ERROR_LINE()
この関数がCATCHブロックで呼び出されると、CATCHブロックが実行される原因となったエラーメッセージの全文が返されます。
テキストには、オブジェクト名、時間、長さなど、置換可能なパラメータに提供された値が含まれています。
例えば:
BEGIN TRY SELECT 200/0; END TRY BEGIN CATCH SELECT ERROR_MESSAGE() AS ErrorMessage; END CATCH; GO
ERROR_LINE
ERROR_LINE関数は、TRYCATCHブロックにエラーがある行の数を返します。
構文:
ERROR_LINE()
関数がCATCHブロックで呼び出されると、エラーが発生した行数が返されます。トリガーまたはストアドプロシージャ内でエラーが発生した場合、そのトリガーまたはストアドプロシージャの行数が返されます。他の関数と同様に、この関数はCATCHブロックのスコープ外で呼び出された場合にNULLを返します。
例えば:
BEGIN TRY SELECT 217/0; END TRY BEGIN CATCH SELECT ERROR_LINE() AS ErrorLine; END CATCH; GO
TRYCATCHコンストラクトの影響を受けないエラー
TRY CATCHブロックは、次の条件をキャッチしません。
- メッセージまたはアラートの情報の重大度は10以下です。
- 重大度20以上のエラーは、セッションのSQLServerデータベースエンジン実行タスクを停止します。
- 発生したエラーの重大度が20以上で、データベース接続が中断されていない場合、TRYCATCHがエラーを処理します。
- クライアント接続の切断や要求の中断などの注意。
- システム管理者を介して、セッションがKILLステートメントで終了したとき。
CATCHブロックで処理されない次のエラータイプは、TRYCATCHコンストラクトと同じ実行レベルで発生します。
- 正当なエラーとしてのコンパイルエラー。
- オブジェクト名解決エラー(オブジェクト名が存在しない)など、ステートメントレベルのコンパイル中に発生するエラーは、名前解決の遅延が原因でコンパイル後に発生します。
例えば:
USE AdventureWorks2109; GO BEGIN TRY SELECT * FROM Nonexistent; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage; END CATCH
投げる
THROWステートメントは例外を発生させ、実行の制御をTRY…CATCH構造体のCATCHブロックに移します。
構文:
THROW [{error_number | @local_varibale}, {message | @local_variable}, {state | @local_variable}] [;]
例えば:
USE tempdb; GO CREATE TABLE dbo.TestRethrow (ID INT PRIMARY KEY); BEGIN TRY INSERT dbo.TestRethrow(ID) VALUES(1); INSERT dbo.TestRethrow(ID) VALUES(1); END TRY BEGIN CATCH PRINT 'In catch block.'; THROW END CATCH;
THROWを使用すると、コマンドのバインドに失敗しても、CATCHブロック内のPRINTステートメントが出力されます。これはSQLServerでのTHROWの役割です。