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)

例外描述

找出最符合你情況的例外情況。 例如,捕捉 IntegrityError / 操作上的INSERT限制違規,以及ProgrammingError開發過程中的 SQLUPDATE 語法問題。 基礎職業只能 Error 當作備案。

例外狀況 當引發時
Warning 資料庫中的非致命警告。
Error 所有資料庫錯誤的基底類別。
InterfaceError 錯誤與資料庫介面(驅動程式)有關,而非資料庫本身。
DatabaseError 與資料庫相關的錯誤。
DataError 因處理資料問題(除以零、值超出範圍)所產生的錯誤。
OperationalError 與資料庫操作相關的錯誤(連線中斷、記憶體配置、交易錯誤)。
IntegrityError 當資料庫完整性受到影響時會出現錯誤(如外鍵違規、唯一限制)。
InternalError 內部資料庫錯誤(游標無效、交易不同步)。
ProgrammingError 程式錯誤(語法錯誤、找不到表格、參數數量錯誤)。
NotSupportedError 資料庫或驅動程式不支援此功能。
ConnectionStringParseError 連接字串 語法無效或關鍵字不明。

基本錯誤處理

使用嘗試除外區塊來處理資料庫錯誤:

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 基底類別的屬性:

Attribute Source 描述
driver_error Python 驅動程式 由 SQLSTATE 選擇的標準化英文文本會從 ODBC 回傳(例如 "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 throttling,請參閱 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 代碼是五個字元的代碼,用來識別錯誤狀況。 前兩個字元表示職業,後面三個字元表示子職業。 你很少需要直接檢查這些代碼。 相反地,請鎖定適當的 Python 例外類型(列於「例外」欄位)。 當你需要區分同一例外類型內的特定錯誤條件時,請使用 SQLSTATE 代碼,例如區分死結(40001)與一般連線失敗(08S01)。

00級 - 成功完成

SQLSTATE 例外狀況 描述
00000 None 成功

01級 - 警告

SQLSTATE 例外狀況 描述
01000 Warning 一般警告
01001 Warning 數據指標作業衝突
01002 Warning 斷線錯誤
01003 資料錯誤 set 函式中排除的 NULL 值
01004 資料錯誤 字串資料,右截斷
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 資料錯誤 字串資料,右截斷
22002 資料錯誤 需要指標變數,但未提供
22003 資料錯誤 超出範圍的數值
22007 資料錯誤 無效的日期時間格式
22008 資料錯誤 日期時間欄位溢位
22012 資料錯誤 除以零
22015 資料錯誤 間隔欄位溢位
22018 資料錯誤 轉換規格的字元值無效
22019 資料錯誤 無效的逸出字元
22025 資料錯誤 無效的逸出序列
22026 資料錯誤 字串數據,長度不符

第23類 - 完整性約束違規

SQLSTATE 例外狀況 描述
23000 完整性錯誤 完整性約束違反(一般)

類別 24 - 游標狀態無效

SQLSTATE 例外狀況 描述
24000 內部錯誤 無效的數據指標狀態

第25類 - 交易狀態無效

SQLSTATE 例外狀況 描述
25000 操作錯誤 交易狀態無效
25S01 操作錯誤 交易狀態不明
25S02 操作錯誤 交易仍然有效
25S03 操作錯誤 交易會被回滾

第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 完整性錯誤 WITH CHECK OPTION 違規

HY 類 - CLI 專屬疾病

SQLSTATE 例外狀況 描述
HY000 資料庫錯誤 一般誤差
HY001 操作錯誤 記憶體配置錯誤
HY003 程式設計錯誤 無效的應用程式緩衝區類型
HY004 程式設計錯誤 無效的 SQL 資料類型
HY007 程式設計錯誤 未備妥相關聯的語句
HY008 操作錯誤 行動取消
HY009 程式設計錯誤 無效的 Null 指標使用
HY010 程式設計錯誤 函式順序錯誤
HY011 程式設計錯誤 無法立即設定屬性
HY012 程式設計錯誤 無效的交易操作代碼
HY013 操作錯誤 記憶體管理錯誤
HY014 操作錯誤 把柄數超過上限
HY015 程式設計錯誤 沒有可用的數據指標名稱
HY016 程式設計錯誤 無法修改實作列描述符
HY017 程式設計錯誤 自動分配描述符句柄的無效使用
HY018 操作錯誤 伺服器拒絕取消請求
HY019 程式設計錯誤 非字元與非二元資料分段傳送
HY020 資料錯誤 嘗試串接空值
HY021 程式設計錯誤 描述符資訊不一致
HY024 程式設計錯誤 無效的屬性值
HY090 程式設計錯誤 無效的字串或緩衝區長度
HY091 程式設計錯誤 無效描述符欄位識別碼
HY092 程式設計錯誤 無效屬性/選項識別碼
HY095 程式設計錯誤 功能類型超出範圍
HY096 程式設計錯誤 無效資訊類型
HY097 程式設計錯誤 欄位類型超出範圍
HY098 程式設計錯誤 望遠鏡類型超出範圍
HY099 程式設計錯誤 可歸零型別超出範圍
HY100 程式設計錯誤 唯一性選項類型超出範圍
HY101 程式設計錯誤 準確度選項類型超出範圍
HY103 程式設計錯誤 無效的取回碼
HY104 程式設計錯誤 無效的有效位數或小數位數值
HY105 程式設計錯誤 無效的參數類型
HY106 程式設計錯誤 取物類型超出範圍
HY107 程式設計錯誤 列值超出範圍
HY109 程式設計錯誤 無效的數據指標位置
HY110 程式設計錯誤 無效驅動程式補全
HY111 程式設計錯誤 書籤值無效
HYC00 非支援錯誤 未實作選擇性功能
HYT00 操作錯誤 逾時已超過
HYT01 操作錯誤 連線已逾時

Class 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() 來清理失敗的交易。 若無明確回滾,連線仍處於交易失敗狀態。