mssql-pythonのエラー処理とSQLSTATEコード

mssql-pythonドライバは、SQL ServerおよびAzure SQL向けの標準的な例外階層、一般的なエラー処理パターン、SQLSTATEコードマッピングを定義しています。

例外階層

mssql-pythonドライバは DB-API 2.0(PEP 249)例外階層に従っています:

Exception (builtins)
├── Warning
└── Error
    ├── InterfaceError
    └── DatabaseError
        ├── DataError
        ├── OperationalError
        ├── IntegrityError
        ├── InternalError
        ├── ProgrammingError
        └── NotSupportedError

ConnectionStringParseError (standalone, not part of hierarchy)

例外の説明

自分の状況に最も合った例外を見つけてください。 例えば、INSERT/UPDATE操作の制約違反をIntegrityErrorキャッチしたり、開発中のSQL構文問題をProgrammingError検知したりします。 基本 Error クラスはあくまで代替手段として利用してください。

例外 持ち上げたとき
Warning データベースからの非致死警告。
Error すべてのデータベースエラーのベースクラス。
InterfaceError データベースインターフェース(ドライバー)に関するエラーであって、データベース自体ではありません。
DatabaseError データベースに関するエラー。
DataError 処理データの問題(ゼロでの割り算、値の範囲外)によるエラー。
OperationalError データベース操作に関連するエラー(接続喪失、メモリ割り当て、トランザクションエラー)。
IntegrityError データベースの整合性が影響を受ける場合のエラー(外部キー違反、一意制約)。
InternalError 内部データベースエラー(カーソル無効、トランザクションの同期外)。
ProgrammingError プログラミングの誤り(構文ミス、テーブルの見つからないこと、パラメータ数の誤り)。
NotSupportedError データベースやドライバーでサポートされていない機能です。
ConnectionStringParseError 無効な接続文字列構文や未知のキーワード。

基本的なエラー処理

データベースエラーを処理するためにtry-exunxブロックを使用します:

import mssql_python

try:
    conn = mssql_python.connect(connection_string)
    cursor = conn.cursor()
    cursor.execute("INSERT INTO Production.Product (Name) VALUES (%(name)s)", {"name": "Test"})
    conn.commit()
except mssql_python.IntegrityError as e:
    print(f"Constraint violation: {e}")
    conn.rollback()
except mssql_python.ProgrammingError as e:
    print(f"SQL syntax error: {e}")
except mssql_python.OperationalError as e:
    print(f"Connection or operational error: {e}")
except mssql_python.Error as e:
    print(f"Database error: {e}")
finally:
    if 'conn' in locals():
        conn.close()

接続を通じたアクセス例外

例外は接続インスタンスで検出できます:

try:
    cursor.execute("INVALID SQL")
except conn.ProgrammingError as e:
    print(f"Caught via connection: {e}")

エラーメッセージの構造

MSSQL-python例外オブジェクトは、ドライバーの Exception ベースクラスから得られる3つの属性を公開します。

特性 Source 形容
driver_error Pythonドライバー ODBCからはSQLSTATEが選んだ標準化された英語テキスト(例: "Communication link failure""Invalid authorization specification""Syntax error or access violation")が返されます。 リリースを越えて安定しています。サブストリングマッチしても安全です。
ddbc_error 直接データベース接続(DDBC) サーバー側のメッセージは、通常 [Microsoft][SQL Server]で始まる。 フォーマットは安定した契約ではありません。
message 構成 f"Driver Error: {driver_error}; DDBC Error: {ddbc_error}"。 これが str(exc) が返すものだ。
try:
    cursor.execute("SELECT * FROM no_such_table;")
except mssql_python.ProgrammingError as exc:
    print(exc.driver_error)  # Base table or view not found
    print(exc.ddbc_error)    # [Microsoft][SQL Server]Invalid object name 'no_such_table'.
    print(exc)               # Driver Error: Base table or view not found; DDBC Error: ...

SQL Serverエンジンのエラー番号(20840501など)は属性として公開されておらず、どちらの文字列にも確実に埋め込まれていません。 例外サブクラスとテキスト driver_error 分類。 Azure SQL スロットリングについては、Retry logic を参照してください。

SQLSTATE分類

mssql-pythonはODBCが返すSQLSTATEを使ってPython例外サブクラスとdriver_errorテキストの両方を選択します。 完全なSQLSTATE→例外マッピングはドライバーソースに exceptions.py されています。 次のセクションでは、SQL ServerおよびAzure SQLで最も頻繁に現れるSQLSTATEを挙げます。

接続エラー

mssql_python.connect()からの接続障害は他の接続障害と同様に、mssql_python.OperationalErrorを上げます。

import mssql_python

try:
    conn = mssql_python.connect(
        "Server=unreachable-server.database.windows.net;"
        "Database=<database>;"
        "Authentication=ActiveDirectoryDefault;"
        "Encrypt=yes"
    )
except mssql_python.OperationalError as e:
    print(f"Connection failed: {e.driver_error}")
    # e.driver_error: "Client unable to establish connection"

接続文字列エラー

接続文字列解析エラーは ConnectionStringParseErrorを発生させます:

try:
    conn = mssql_python.connect("Servr=localhost;")  # Typo
except mssql_python.ConnectionStringParseError as e:
    print(f"Invalid connection string: {e}")
    # Output: Unknown keyword 'Servr'

SQLSTATEコード参照

SQLSTATEコードは、エラー状態を識別するための5文字コードです。 最初の2文字はクラスを示し、最後の3文字はサブクラスを示します。 これらのコードを直接確認する必要はほとんどありません。 代わりに、適切なPython例外タイプ(「例外」欄に記載)を検出してください。 同じ例外タイプ内で特定のエラー条件を区別する必要がある場合、例えばデッドロック(40001)と一般的な接続障害(08S01)を区別するためにSQLSTATEコードを使用してください。

クラス00 - 成功した完成

SQLSTATE 例外 形容
00000 なし 成功

クラス01 - 警告

SQLSTATE 例外 形容
01000 Warning 一般的な警告
01001 Warning カーソル操作の競合
01002 Warning 切断エラー
01003 DataError set 関数で NULL 値が削除される
01004 DataError 文字列データ、右切り捨て
01006 Warning 特権が取り消されない
01007 Warning 特権が付与されていません
01S00 Warning 無効な接続文字列属性
01S01 Warning エラー・イン・ロー
01S02 Warning オプション値の変更

クラス07 - 動的SQLエラー

SQLSTATE 例外 形容
07001 プログラミングエラー パラメータの数が間違っている
07002 プログラミングエラー COUNT フィールドが正しくありません
07005 プログラミングエラー カーソル仕様ではなく準備文
07006 プログラミングエラー 制限付きデータ型属性違反
07009 プログラミングエラー 無効な記述子インデックス
07S01 プログラミングエラー 既定のパラメーターの使用が無効です

クラス08 - 接続例外

SQLSTATE 例外 形容
08001 オペレーショナルエラー クライアントが接続を確立できない
08002 オペレーショナルエラー 使用中の接続名
08003 オペレーショナルエラー 接続は存在しません
08004 オペレーショナルエラー サーバーが接続を拒否しました
08007 オペレーショナルエラー トランザクション中の接続障害
08S01 オペレーショナルエラー 通信リンクエラー

クラス21 - 濃度違反

SQLSTATE 例外 形容
21S01 プログラミングエラー 挿入する値の一覧が列の一覧と一致しません
21S02 プログラミングエラー 派生テーブルの次数が列リストと一致しない

クラス22 - データ例外

SQLSTATE 例外 形容
22001 DataError 文字列データ、右切り捨て
22002 DataError インジケーター変数は必須ですが、指定されていません
22003 DataError 範囲外の数値
22007 DataError datetime 形式が無効です
22008 DataError Datetime フィールドオーバーフロー
22012 DataError 0 で除算しました
22015 DataError 間隔フィールドのオーバーフロー
22018 DataError キャスト指定の文字値が無効です
22019 DataError エスケープ文字が無効です
22025 DataError エスケープ シーケンスが無効です
22026 DataError 文字列データの長さが合致しません

クラス23 - 完全性制約違反

SQLSTATE 例外 形容
23000 IntegrityError 整合性制約違反(一般)

クラス24 - 無効カーソル状態

SQLSTATE 例外 形容
24000 内部エラー カーソル状態が無効

クラス25 - 無効な取引状態

SQLSTATE 例外 形容
25000 オペレーショナルエラー 無効トランザクション状態
25シーズン第1期 オペレーショナルエラー 取引状態不明
25シーズン2 オペレーショナルエラー 取引はまだ有効です
25シーズン3 オペレーショナルエラー トランザクションはロールバックされます

クラス28 - 無効な認可仕様

SQLSTATE 例外 形容
28000 オペレーショナルエラー 無効な認可仕様(ログイン失敗)

クラス34 - カーソル名が無効です

SQLSTATE 例外 形容
34000 プログラミングエラー カーソル名が無効

クラス3C - 重複カーソル名

SQLSTATE 例外 形容
3C000 プログラミングエラー 重複するカーソル名

クラス3D - カタログ名が無効です

SQLSTATE 例外 形容
3D000 プログラミングエラー カタログ名が無効です

クラス3F - スキーマ名が無効です

SQLSTATE 例外 形容
3F000 プログラミングエラー 無効なスキーマ名

クラス40 - トランザクションロールバック

SQLSTATE 例外 形容
40001 オペレーショナルエラー シリアライゼーションの失敗(デッドロック)
40002 オペレーショナルエラー 整合性制約違反によりロールバックが発生しました
40003 オペレーショナルエラー ステートメントの入力候補が不明です

クラス42 - 構文エラーまたはアクセスルール違反

SQLSTATE 例外 形容
42000 プログラミングエラー 構文エラーまたはアクセス違反
42S01 プログラミングエラー ベース テーブルまたはビューが既に存在する
42S02 プログラミングエラー ベース テーブルまたはビューが見つかりません
42S11 プログラミングエラー インデックスは既に存在します
42S12 プログラミングエラー インデックスが見つかりません
42S21 プログラミングエラー 列は既に存在します
42S22 プログラミングエラー 列が見つかりません

クラス44 - チェックオプション違反

SQLSTATE 例外 形容
44000 IntegrityError WITH CHECK OPTION 違反

クラスHY - CLI特有疾患

SQLSTATE 例外 形容
HY000 DatabaseError 一般的なエラー
HY001 オペレーショナルエラー メモリ割り当てエラー
HY003 プログラミングエラー 無効なアプリケーション バッファーの種類
HY004 プログラミングエラー SQL データ型が無効です
HY007 プログラミングエラー 関連付けられたステートメントが準備されていません
HY008 オペレーショナルエラー 操作が取り消されました
HY009 プログラミングエラー null ポインターの使用が無効です
HY010 プログラミングエラー 関数シーケンス エラー
HY011 プログラミングエラー 現在、属性を設定できません
HY012 プログラミングエラー 無効なトランザクション操作コード
HY013 オペレーショナルエラー メモリ管理エラー
HY014 オペレーショナルエラー ハンドル数の上限を超えた
HY015 プログラミングエラー 使用可能なカーソル名がありません
HY016 プログラミングエラー 実装行ディスクリプタを変更できません
HY017 プログラミングエラー 自動割り当てディスクリプタハンドルの不正な使用について
HY018 オペレーショナルエラー サーバーはキャンセルリクエストを拒否しました
HY019 プログラミングエラー 非文字および非バイナリデータが分割で送信される
HY020 DataError null 値の連結を試みる
HY021 プログラミングエラー 記述子情報の不整合
HY024 プログラミングエラー 属性値が無効です
HY090 プログラミングエラー 文字列またはバッファーの長さが無効です
HY091 プログラミングエラー 無効なディスクリプタフィールド識別子
HY092 プログラミングエラー 無効な属性/オプション識別子
HY095 プログラミングエラー 関数型が範囲外
HY096 プログラミングエラー 無効な情報型
HY097 プログラミングエラー カラムタイプの範囲外
HY098 プログラミングエラー スコープの種類が範囲外
HY099 プログラミングエラー 無効型の範囲外
HY100 プログラミングエラー 一意性オプションの種類が範囲外
HY101 プログラミングエラー 精度オプションの種類が範囲外
HY103 プログラミングエラー 無効な取得コード
HY104 プログラミングエラー 有効桁数またはスケール値が無効です
HY105 プログラミングエラー パラメーターの型が無効です
HY106 プログラミングエラー フェッチタイプが範囲外
HY107 プログラミングエラー 行の値が範囲外
HY109 プログラミングエラー カーソル位置が無効です
HY110 プログラミングエラー 無効ドライバー完了
HY111 プログラミングエラー 無効なブックマーク値
HYC00 NotSupportedError 省略可能な機能が実装されていません
HYT00 オペレーショナルエラー タイムアウトの期限が切れました
HYT01 オペレーショナルエラー 接続がタイムアウトしました

クラスIM - ドライバーマネージャーエラー

SQLSTATE 例外 形容
IM001 インターフェースエラー ドライバーは、この関数をサポートしていません
IM002 インターフェースエラー データソース名が見つかりません
IM003 インターフェースエラー 指定されたドライバーを読み込めませんでした
IM004 インターフェースエラー ドライバーのSQLAllocHandleがSQL_HANDLE_ENVで失敗しました
IM005 インターフェースエラー ドライバーのSQLAllocHandleが失敗SQL_HANDLE_DBC
IM006 インターフェースエラー Driver's SQLSetConnectAttr failed
IM007 インターフェースエラー データソースやドライバーの指定はありません
IM008 インターフェースエラー 対話が失敗
IM009 インターフェースエラー 翻訳 DLL を読み込むことができません
IM010 インターフェースエラー データ ソース名が長すぎます
IM011 インターフェースエラー ドライバー名が長すぎます
IM012 インターフェースエラー DRIVER キーワード構文エラー
IM014 インターフェースエラー 無効なDSN
IM015 インターフェースエラー 破損したファイルデータソース

一般的なSQL Serverエラー番号

SQLSTATE以外にも、SQL Serverはカッコ内にネイティブのエラー番号を提供します。 これらはアプリケーションコードで最も遭遇しやすいエラーです。 リトライロジックはエラー1205(デッドロック)と一時的な接続エラー( リトライロジック参照)を中心に構築します。

エラー メッセージ パターン Resolution
208 無効なオブジェクト名 テーブルやビューが存在するか確認し、スキーマの資格も確認してください。
547 制約違反 外部キーまたはチェック制約が失敗した場合。
2627 一意制約違反 重複したキーの価値が挿入されました。
2601 一意インデックス違反 インデックスには重複キーが存在します。
4060 データベースを開くことができません データベースは存在しないか、アクセスが拒否されています。
18456 ログインに失敗しました 認証失敗。 資格を確認してください。
1205 デッドロックの被害者 このトランザクションはロールバックされました。 操作を再試行してください。

症状から例外へのクイック参照

この表を使って、よくある症状を検出すべき例外タイプにマッピングします:

症状 例外 考えられる原因
「ユーザーのログインに失敗」 OperationalError 認証情報が間違っているか、ユーザーがデータベースにマッピングされていない場合もあります。
「クライアントが接続を確立できません」 OperationalError サーバーにアクセスできない、ファイアウォール、またはDNSの問題。
「タイムアウト終了」 OperationalError クエリまたは接続タイムアウト。 タイムアウトを増やすかクエリを最適化しましょう。
「無効なオブジェクト名」 ProgrammingError テーブルが存在せず、スキーマも指定されていません。
「誤った構文」 ProgrammingError SQLの構文エラー。 SSMSでのテストクエリ。
「パラメータの数が間違っている」 ProgrammingError パラメータ数がプレースホルダーと一致しません。
「プライマリキー違反」 IntegrityError 鍵の複製。 MERGEを使うか、挿入前に確認してください。
「外国鍵の違反」 IntegrityError 参照された行は存在しません。 まず親を挿入してください。
「取引は行き詰まっていた」 OperationalError (誤差1205) ロック争い。 再試行ロジックを実装します。
「文字列やバイナリデータは切り詰められる」 DataError 値が列長を超えます。 データを確認するか、カラムサイズを増やしてください。
「転換失敗」 DataError 型が一致しません。 列には正しいPython型を使いましょう。
「不明キーワード」 ConnectionStringParseError 「接続文字列」キーワードにタイプミスがあります。
「Callprocはサポートされていません」 NotSupportedError cursor.execute("EXECUTE ...") を代わりに使用します。

ベスト プラクティス

  • 一般的な例外よりも、具体的な例外を優先してください。 最も具体的(IntegrityError)から最も具体的でない(Error)順に並べます。
  • データ改変操作には必ずIntegrityErrorを処理してください。 制約違反は通常の動作(例えば、ユーザーが重複ユーザー名を作成しようとするなど)で予想されます。
  • トラブルシューティングのために、エラーの全文脈を記録してください。 例外は driver_error (安定的、SQLSTATE由来のテキスト)と ddbc_error (サーバー側メッセージ)を公開します。 両方記録してください;分類は driver_error
  • 一時的なエラー(接続障害、デッドロック)に対してリトライロジックを実装します。 リ トライロジックを参照してください。
  • 例外ハンドラでrollback()を使って失敗したトランザクションをクリーンアップします。 明示的なロールバックがなければ、接続はトランザクション失敗状態のままです。