หมายเหตุ
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลอง ลงชื่อเข้าใช้หรือเปลี่ยนไดเรกทอรีได้
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลองเปลี่ยนไดเรกทอรีได้
Use this article to diagnose query execution, data type, performance, transaction, and bulk copy issues with the mssql-python driver.
Query execution issues
Table or object not found
Symptoms:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Possible causes and solutions:
Incorrect database context
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Schema not specified
cursor.execute("SELECT * FROM dbo.TableName")Table doesn't exist
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Syntax error
Symptoms:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Solutions:
Test the SQL statement in SQL Server Management Studio (SSMS) to verify the syntax.
Use a parameterized query instead of string interpolation:
# Don't use string interpolation for query parameters. cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'") # Use parameters. cursor.execute( "SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name}, )
Parameter errors
Symptoms:
ProgrammingError: [07001] Wrong number of parameters
Solutions:
Count the placeholders and parameters. The counts must match.
Choose the correct parameter style:
# Qmark style: positional parameters cursor.execute( "SELECT * FROM Production.Product " "WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"), ) print(cursor.fetchone()) # Pyformat style: named parameters cursor.execute( "SELECT * FROM Production.Product " "WHERE ProductID = %(id)s AND Name LIKE %(name)s", {"id": 1, "name": "Adjustable%"}, ) print(cursor.fetchone())
Data type issues
Datetime conversion errors
Symptoms:
DataError: [22007] Invalid datetime format
Solution:
Use Python datetime objects instead of strings.
from datetime import datetime
cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")
# This value raises an error because the date is invalid.
try:
cursor.execute(
"INSERT INTO #Events (EventDate) VALUES (%(event_date)s)",
{"event_date": "2024-13-45"},
)
except Exception as e:
print(f"Expected error: {e}")
# Use a Python datetime object.
cursor.execute(
"INSERT INTO #Events (EventDate) VALUES (%(event_date)s)",
{"event_date": datetime(2024, 3, 15)},
)
cursor.execute("SELECT EventDate FROM #Events")
print(cursor.fetchone())
Decimal precision issues
Symptoms:
Numbers appear truncated or rounded incorrectly.
Solution:
Use decimal.Decimal for precise numeric values:
from decimal import Decimal
cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10, 2))")
cursor.execute(
"INSERT INTO #PriceDemo (ListPrice) VALUES (%(list_price)s)",
{"list_price": Decimal("19.99")},
)
Unicode encoding issues
Symptoms:
Special characters appear garbled or cause errors.
Solutions:
Use nvarchar columns for Unicode data in your database.
Pass strings directly. The driver handles encoding:
cursor.execute("CREATE TABLE #UnicodeDemo (Name NVARCHAR(50))") cursor.execute( "INSERT INTO #UnicodeDemo (Name) VALUES (%(name)s)", {"name": "日本語"}, ) cursor.execute("SELECT Name FROM #UnicodeDemo") print(cursor.fetchone())
Performance issues
Slow query execution
Possible causes and solutions:
Missing indexes: Check the query execution plan in SSMS.
Large result sets: Use
fetchmany()instead offetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Connection pooling disabled: Enable pooling:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Memory issues with large results
Symptoms:
The Python process runs out of memory.
Solutions:
Stream results instead of loading all rows into memory.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Use server-side pagination.
page_size = 1000 offset = 0 while True: cursor.execute( "SELECT * FROM LargeTable ORDER BY ID " "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", (offset, page_size), ) rows = cursor.fetchall() if not rows: break process_rows(rows) offset += page_size
Transaction issues
Temp table scoping with autocommit
Session temp tables (#tablename) you create inside a transaction disappear when the transaction rolls back. This behavior commonly causes confusion when autocommit is off, which is the default:
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
# An explicit rollback or an error removes #TempData.
conn.rollback()
# This statement fails with "Invalid object name '#TempData'".
cursor.execute("SELECT * FROM #TempData")
Commit immediately after you create a temp table, or use autocommit mode:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
DDL statements that require autocommit mode, such as CREATE DATABASE, fail inside an open transaction. Set autocommit before you run them:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transaction not committed
Symptoms:
Data changes don't persist after you close the connection.
Solution:
With autocommit=False, which is the default, call commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternatively, use autocommit mode:
conn = mssql_python.connect(connection_string, autocommit=True)
Deadlock errors
Symptoms:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
Retry logic handles the immediate failure, but recurring deadlocks indicate a design problem. Capture the deadlock graph, and analyze the statements and lock types. Common fixes include these changes:
- Reorder operations so competing transactions acquire locks in the same sequence.
- Reduce the transaction scope.
- Add appropriate indexes to reduce lock duration.
For a full walkthrough of deadlock analysis, see Deadlocks guide. If you use Azure SQL Database, see Analyze and prevent deadlocks.
Bulk load issues
Constraint violations during bulkcopy
Symptoms:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Cause:
Data in your batch violates table constraints such as primary key, unique, check, or foreign key constraints.
Solution:
Validate data before you load it. For large datasets, load the data into a staging table, and then merge it into the target:
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)
# Check for duplicate rows before the merge.
cursor.execute("""
SELECT s.ID
FROM ##Staging AS s
INNER JOIN dbo.Target AS t
ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
print(f"Skipping {len(dupes)} duplicate rows")
# Insert rows that don't exist in the target.
cursor.execute("""
INSERT INTO dbo.Target (ID, Name)
SELECT s.ID, s.Name
FROM ##Staging AS s
WHERE NOT EXISTS (
SELECT 1
FROM dbo.Target AS t
WHERE t.ID = s.ID
)
""")
conn.commit()
For upsert patterns with staging tables, see Data loading and movement patterns.
Column mapping errors
Symptoms:
RuntimeError: Bulk copy failure - column count mismatch
Cause:
The number of columns in your data doesn't match the target table column count, or the columns are in the wrong order.
Solution:
Ensure that your data matches the table schema in order and count:
from decimal import Decimal
cursor.execute("""
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable'
ORDER BY ORDINAL_POSITION
""")
for col in cursor.fetchall():
print(col)
rows = [
(1, "Widget", Decimal("19.99")),
(2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)
Type mismatches during bulkcopy
Symptoms:
Data loads, but values are truncated, rounded, or incorrect.
Cause:
Python values don't map cleanly to the target column types. Common examples include float values loaded into decimal columns, which can lose precision, and oversized strings loaded into fixed-length columns.
Solution:
Use Python types that match your schema:
from decimal import Decimal
rows = [
# Use Decimal for decimal and numeric columns.
(1, "Widget", Decimal("19.99")),
# Avoid float values because they can lose precision.
# (1, "Widget", 19.99),
]
cursor.bulkcopy("dbo.Products", rows)
NumPy type binding failures
Symptoms:
Parameters silently fail or raise data type errors when you use NumPy integer or float types.
Cause:
NumPy types such as numpy.int64 and numpy.int32 don't pass isinstance(x, int) in NumPy 2.x. The driver's type inference doesn't recognize them, which causes unexpected behavior.
Solution:
Convert NumPy values to native Python types before you bind them:
import numpy as np
cursor.execute(
"SELECT * FROM Production.Product WHERE ProductID = %(product_id)s",
{"product_id": int(np.int64(42))},
)
for _, row in df.iterrows():
cursor.execute(
"INSERT INTO #Orders (ProductID, Qty) "
"VALUES (%(product_id)s, %(qty)s)",
{
"product_id": int(row["ProductID"]),
"qty": int(row["Qty"]),
},
)
For larger datasets, use the Arrow or pandas integration paths. These paths handle type conversion internally.
Bulk copy with temp tables
Symptoms:
cursor.bulkcopy("#TempTable", data) raises RuntimeError: Invalid object name '#TempTable'.
Cause:
bulkcopy() can't resolve session temp tables (#tablename) because of metadata lookup limitations. Global temp tables (##tablename) and permanent tables work.
Solution:
Use a global temp table or a regular staging table:
# A global temp table is visible to all sessions and is dropped
# when the last session disconnects.
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)
# Alternatively, use a permanent staging table.
cursor.execute("CREATE TABLE dbo.Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("dbo.Staging", rows)
For small datasets where you prefer a session temp table, use executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)