mssql-python 驅動程式提供用於 SQL 查詢執行、參數化查詢、批次操作及預備語句的游標方法。
基本查詢執行程序
使用游標 execute() 方法來執行 SQL 語句:
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("SELECT Name, ListPrice FROM Production.Product WHERE Color = 'Black'")
rows = cursor.fetchall()
for row in rows:
print(row.Name, row.ListPrice)
cursor.close()
conn.close()
參數化查詢
務必使用參數化查詢以防止 SQL 注入。 驅動程式的預設參數樣式為 pyformat (命名佔位符),但它也支援 qmark (位置佔位符)。 使用 qmark 來表示 ODBC {CALL} 逸出序列。
Pyformat 風格(預設)
使用帶有 %(name)s 語法的命名佔位符並傳遞字典:
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE Color = %(color)s AND ListPrice > %(price)s",
{"color": "Black", "price": 10.00}
)
Qmark 風格
使用含有 ? 的位置佔位符,並傳入元組或清單:
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = ? AND ListPrice > ?",
(1, 10.00)
)
驅動程式會根據你的 SQL 查詢和參數類型自動偵測參數樣式。
INSERT、UPDATE、DELETE作業
對於資料修改語句,請使用參數化查詢並提交交易:
cursor.execute("CREATE TABLE #ExecDemo (Name NVARCHAR(50), CategoryID INT, Price DECIMAL(10,2))")
cursor.execute(
"INSERT INTO #ExecDemo (Name, CategoryID, Price) VALUES (%(name)s, %(category)s, %(price)s)",
{"name": "New Product", "category": 1, "price": 19.99}
)
conn.commit()
print(f"Rows affected: {cursor.rowcount}")
使用 executemany() 進行批次執行
用 executemany() 來有效率地插入多列。 驅動程式使用逐欄參數綁定以提升高效能:
products = [
{"name": "Product A", "category": 1, "price": 10.00},
{"name": "Product B", "category": 1, "price": 15.00},
{"name": "Product C", "category": 2, "price": 20.00},
]
cursor.execute("CREATE TABLE #BatchDemo (Name NVARCHAR(50), CategoryID INT, Price DECIMAL(10,2))")
cursor.executemany(
"INSERT INTO #BatchDemo (Name, CategoryID, Price) VALUES (%(name)s, %(category)s, %(price)s)",
products
)
conn.commit()
print(f"Rows inserted: {cursor.rowcount}")
採用 qmark 樣式:
products = [
("Product A", 1, 10.00),
("Product B", 1, 15.00),
("Product C", 2, 20.00),
]
cursor.execute("CREATE TABLE #QmarkDemo (Name NVARCHAR(50), CategoryID INT, Price DECIMAL(10,2))")
cursor.executemany(
"INSERT INTO #QmarkDemo (Name, CategoryID, Price) VALUES (?, ?, ?)",
products
)
conn.commit()
多語句批次執行
在連線上使用 batch_execute() ,在單一呼叫中執行多個不同的語句:
results, cursor = conn.batch_execute(
[
"CREATE TABLE #BatchExec (Name NVARCHAR(50), CategoryID INT)",
"INSERT INTO #BatchExec (Name, CategoryID) VALUES (%(name)s, %(cat)s)",
"SELECT COUNT(*) FROM #BatchExec"
],
[
None, # No params for CREATE
{"name": "New Item", "cat": 1}, # Params for INSERT
None # No params for SELECT
]
)
print(f"CREATE result: {results[0]}")
print(f"INSERT affected: {results[1]} rows")
print(f"Row count: {results[2][0][0]}")
備妥語句
驅動程式預設會準備查詢(use_prepare=True)。 當你在同一游標上多次執行同一個 SQL 字串時,驅動程式會在後續呼叫時自動重用已準備好的語句:
# First execution prepares the statement
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = %(subcategory_id)s",
{"subcategory_id": 1},
)
rows1 = cursor.fetchall()
# Same SQL string on same cursor → driver reuses the prepared plan
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = %(subcategory_id)s",
{"subcategory_id": 2},
)
rows2 = cursor.fetchall()
若要跳過準備程序,改為直接執行:
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = 1",
use_prepare=False # Uses SQLExecDirectW instead of SQLPrepareW
)
連線層級執行
對於簡單的一次性查詢,直接在連線上使用 execute() :
# Creates cursor, executes, and returns cursor
cursor = conn.execute("SELECT TOP 10 Name, ListPrice FROM Production.Product")
rows = cursor.fetchall()
cursor.close()
預存程序
使用 EXECUTE 或 ODBC {CALL} 逸出語法來呼叫儲存程序。 關於輸出參數、多重結果集及交易模式的資訊,請參見 儲存程序。
cursor.execute(
"EXECUTE dbo.uspGetManagerEmployees @BusinessEntityID = %(business_entity_id)s",
{"business_entity_id": 16}
)
rows = cursor.fetchall()
設定輸入大小
可明確 setinputsizes() 宣告參數型別,這能提升批次操作的效能:
cursor.setinputsizes([
(mssql_python.SQL_WVARCHAR, 50, 0), # NVARCHAR(50)
(mssql_python.SQL_INTEGER, 0, 0), # INT
])
cursor.executemany(
"SELECT ProductID, Name FROM Production.Product WHERE Name LIKE ? AND ProductSubcategoryID = ?",
[("Road%", 2), ("Mountain%", 1)]
)
Note
並非所有 SQL 型別常數都可搭配 setinputsizes() 使用。
SQL_WVARCHAR 和 SQL_INTEGER 都很可靠。 對於十進位值,請使用驅動程式的自動型別推論,而非 SQL_DECIMAL,後者有已知問題(GitHub #503)。
錯誤處理
將資料庫操作包裝成 try-except 區塊:
try:
cursor.execute("CREATE TABLE #ErrDemo (Name NVARCHAR(50) NOT NULL)")
cursor.execute("INSERT INTO #ErrDemo (Name) VALUES (%(name)s)", {"name": None})
conn.commit()
except mssql_python.IntegrityError as e:
print(f"Constraint violation: {e}")
conn.rollback()
except mssql_python.ProgrammingError as e:
print(f"SQL error: {e}")
conn.rollback()
最佳做法
- 務必使用參數化查詢 以防止 SQL 注入。
-
進行大量插入時,請使用 大量複製,而非多次
execute()呼叫。 - 關閉自動提交時,請明確提交交易。
- 關閉游標和連線以便釋放資源。
- 使用上下文管理器 進行自動資源清理:
with mssql_python.connect(connection_string) as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT TOP 5 Name, ListPrice FROM Production.Product")
rows = cursor.fetchall()
# Connection and cursor automatically closed