Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der mssql-python-Treiber ist Microsofts hauseigener Python-Treiber für Microsoft SQL. Wenn Sie eine von Microsoft getreue Treiberoption bevorzugen, bietet sie Folgendes an:
- Keine externe ODBC-Treiberabhängigkeit.
- Eingebautes Verbindungspooling.
- Moderne Unterstützung für Python 3.10+
- Native Microsoft Entra-Authentifizierung.
Wichtige Unterschiede
| Funktion | pyodbc | mssql-python |
|---|---|---|
| Parameterstil |
qmark (?) |
qmark (?) und pyformat (%(name)s) |
| ODBC-Fahrer erforderlich | Ja | No |
| Verbindungspooling | Extern | Integriert |
| Mindestversion von Python | 3.6 | 3.10 |
callproc() |
Unterstützt | Nicht implementiert |
| Autocommit Standard | Off | Off |
Grundlegende Migrationsschritte
Die folgenden Schritte behandeln die Schlüsseländerungen, um eine Pyodbc-Anwendung auf mssql-python zu migrieren.
1. Importe aktualisieren
Ersetzen Sie den Import pyodbc durch mssql_python:
Vorher (pyodbc):
import pyodbc
Nach (mssql-python):
import mssql_python
2. Verbindungsstrings aktualisieren
Entfernen Sie das DRIVER= Schlüsselwort und aktualisieren Sie die Authentifizierungsmethode:
Vorher (pyodbc, benötigt ODBC-Treiber):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
Danach (mssql-python, kein Treiber erforderlich, verwendet Microsoft Entra-Authentifizierung):
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
3. Halten Sie Ihre Anfragen unverändert
Der mssql-python-Treiber unterstützt sowohl ? (qmark) als auch %(name)s (pyformat) Parameterstile. Ihre bestehenden ? Abfragen funktionieren ohne Änderungen:
Vorher (pyodbc):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
Danach (mssql-python, gleiche Abfrage):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
4. Executemany unverändert beibehalten
Bestehende executemanyAufrufe mit Tupeln und ?-Markierungen funktionieren ohne Änderungen:
Vorher (pyodbc):
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)
Danach (mssql-python, gleicher Code):
cursor.execute("DROP TABLE IF EXISTS #MigrateDemo")
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)
Migration von gespeicherten Prozeduren
Der mssql-python-Treiber implementiert callproc()nicht . Die folgenden Abschnitte zeigen, wie man stattdessen verwendet EXECUTE .
Verwenden Sie EXECUTE für gespeicherte Prozeduren
Der pyodbc-Treiber unterstützt callproc(), aber der mssql-python-treiber nicht. Verwenden Sie EXECUTE stattdessen:
Vorher (pyodbc):
cursor.callproc("dbo.uspGetEmployeeManagers", (5,))
results = cursor.fetchall()
Nach (mssql-python):
cursor.execute(
"EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s",
{"id": 5}
)
results = cursor.fetchall()
print(f"Got {len(results)} rows")
Ausgabeparameter
Verwenden Sie T-SQL-Variablen, um Ausgabewerte zu erfassen, anstatt sich auf callproc() Ausgabeparameter zu verlassen:
Vorher (pyodbc, mit callproc):
params = (category_id, pyodbc.SQL_INTEGER)
cursor.callproc("dbo.GetProductCount", params)
count = params[1].value
Danach (mssql-python, unter Verwendung von T-SQL-Variablen):
cursor.execute(
"""
DECLARE @count INT;
SELECT @count = COUNT(*) FROM Production.Product
WHERE ProductSubcategoryID = %(cat_id)s;
SELECT @count AS ProductCount;
""",
{"cat_id": 1}
)
product_count = cursor.fetchval()
print(f"Product count: {product_count}")
Merkmalsspezifische Migrationen
Die folgenden Abschnitte behandeln spezifische pyodbc-Funktionen und deren mssql-python-Äquivalente.
Verbindungszeichenfolgen
| Pyodbc-Schlüsselwort | mssql-python Schlüsselwort | Hinweise |
|---|---|---|
DRIVER={...} |
Nicht erforderlich | Der ODBC-Treiber ist intern gebündelt. |
SERVER= |
Server= |
Keine Verhaltensänderung. |
DATABASE= |
Database= |
Keine Verhaltensänderung. |
Trusted_Connection= |
Trusted_Connection= |
Keine Verhaltensänderung. |
UID= / PWD= |
UID= / PWD= |
Keine Verhaltensänderung. |
Authentication= |
Authentication= |
Akzeptiert dieselben Werte. |
Autocommit
Das Autocommit-Verhalten ist bei beiden Treibern identisch:
Pyodbc:
conn.autocommit = True
pyodbc.connect(connection_string, autocommit=True)
mssql-python:
conn.autocommit = True
Schüttguteinsätze
Um große INSERT Chargen zu beschleunigen, setzen pyodbc-Nutzer fast_executemany = True. Der mssql-python-Treiber optimiert executemany bereits für parametrisierte Batches, daher benötigen moderate Einfügungen kein spezielles Flag. Für große Datenmengen verwenden Sie vorzugsweise bulkcopy(), da hiermit Zeilen über das Bulk-Copy-Protokoll gestreamt werden und dies viel schneller ist als das einzelne Ausführen von INSERT-Anweisungen. Für den vollständigen Workflow siehe Massekopie verwenden.
Pyodbc:
cursor.fast_executemany = True
cursor.executemany(query, data)
Nach (mssql-python) moderate Batches mit executemany:
cursor.execute("DROP TABLE IF EXISTS #BulkTarget")
cursor.execute("CREATE TABLE #BulkTarget (ID INT, Name NVARCHAR(50))")
data = [(i, f"Item {i}") for i in range(100)]
cursor.executemany("INSERT INTO #BulkTarget (ID, Name) VALUES (?, ?)", data)
conn.commit()
Nach (mssql-python), große Datenlasten mit bulkcopy (bevorzugt):
cursor.execute("IF OBJECT_ID('##BulkTarget') IS NOT NULL DROP TABLE ##BulkTarget")
cursor.execute("CREATE TABLE ##BulkTarget (ID INT, Name NVARCHAR(50))")
conn.commit() # Commit DDL before bulkcopy
data = [(i, f"Item {i}") for i in range(100)]
result = cursor.bulkcopy("##BulkTarget", data)
print(f"Bulk copied {result['rows_copied']} rows")
cursor.execute("DROP TABLE ##BulkTarget")
conn.commit()
Reihenfabrik
Der mssql-python-Treiber gibt standardmäßig RowObjekte zurück, die den Attributzugriff unterstützen, ohne dass eine benutzerdefinierte Row-Factory erforderlich ist:
Pyodbc (Custom Row Factory):
def namedtuple_row_factory(cursor):
from collections import namedtuple
columns = [col[0] for col in cursor.description]
Row = namedtuple("Row", columns)
return Row
mssql-python (standardmäßig attributzugriff):
cursor.execute("SELECT Name, ListPrice FROM Production.Product")
row = cursor.fetchone()
print(row.Name) # Attribute access works directly
print(row[0]) # Index access also works
Fehlerbehandlung
Der mssql-python-Treiber verwendet dieselbe Ausnahmehierarchie wie pyodbc, daher benötigen die meisten Ausnahmehandler nur eine Modulnamensänderung.
Ausnahmehierarchie
Die Namen der Ausnahmeklassen werden direkt zwischen den Treibern abgebildet:
Pyodbc:
try:
cursor.execute(query)
except pyodbc.Error as e:
pass
except pyodbc.DatabaseError as e:
pass
except pyodbc.OperationalError as e:
pass
mssql-python:
try:
cursor.execute("SELECT TOP 1 * FROM Production.Product")
print(cursor.fetchone())
except mssql_python.Error as e:
pass
except mssql_python.DatabaseError as e:
pass
except mssql_python.OperationalError as e:
pass
Fehlerdetails
Beide Treiber liefern Fehlerdetails durch Ausnahmeargumente:
Pyodbc:
try:
cursor.execute(query)
except pyodbc.Error as e:
sqlstate = e.args[0]
message = e.args[1]
mssql-python:
try:
cursor.execute("SELECT TOP 1 * FROM NonExistentTable_XYZ")
except mssql_python.Error as e:
# Error message contains SQLSTATE and details
print(str(e))
Verbindungspooling
Der mssql-python-Treiber enthält standardmäßig Connection Pooling, sodass externe Pooling-Bibliotheken nicht mehr benötigt werden.
Externes Pooling entfernen
Wenn du externes Pooling mit pyodbc verwendet hast, hat der mssql-python-Treiber das eingebaut:
Vor (externer pyodbc-Pool):
from dbutils.pooled_db import PooledDB
pool = PooledDB(pyodbc, 5, driver="{ODBC Driver 18 for SQL Server}",
server="your_server", database="your_database",
uid="your_username", pwd="your_password")
conn = pool.connection()
Nach (mssql-python integriertes Pooling):
conn = mssql_python.connect(connection_string)
conn.close()
Pool konfigurieren
Überschreiben Sie die Standard-Poolgröße und den Timeout-Wert mit mssql_python.pooling():
import mssql_python
mssql_python.pooling()
Vollständiges Migrationsbeispiel
Das Folgende zeigt dieselbe Funktion, die mit pyodbc geschrieben und dann mit mssql-python neu geschrieben wurde.
Vorher (pyodbc)
Diese Version verwendet den pyodbc-Verbindungszeichenfolge mit einem DRIVER Schlüsselwort:
import pyodbc
from datetime import date
def get_orders(customer_id: int, start_date: date):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ? AND OrderDate >= ?
ORDER BY OrderDate DESC
""", (customer_id, start_date))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Danach (mssql-python)
Diese Version entfernt das DRIVER Schlüsselwort. Alle Abfragen, Parameter und Zeilenzugriffsmuster bleiben identisch:
import mssql_python
from datetime import date
def get_orders(customer_id: int, start_date: date):
conn = mssql_python.connect(
"Server=localhost;"
"Database=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ? AND OrderDate >= ?
ORDER BY OrderDate DESC
""", (customer_id, start_date))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Die einzigen Änderungen sind die Import-Anweisung und die Verbindungszeichenfolge (kein DRIVER Schlüsselwort erforderlich). Jede Abfrage, jeder Parameter, jedes Abrufmuster und jeder Zeilenzugriff bleibt identisch.
Testen der Migration
Führen Sie vor Abschluss der Migration dieselben Abfragen bei beiden Fahrern durch und vergleichen Sie die Ergebnisse, um gleichwertiges Verhalten zu bestätigen.
Überprüfen Sie das äquivalente Verhalten
Verwenden Sie eine Vergleichsfunktion, die dieselbe Abfrage gegen beide Treiber ausführt und die Ergebnisübereinstimmung bestätigt:
import pyodbc
import mssql_python
def compare_results(pyodbc_conn_str: str, mssql_conn_str: str, query: str):
"""Compare results from both drivers."""
# pyodbc query
pyodbc_conn = pyodbc.connect(pyodbc_conn_str)
pyodbc_cursor = pyodbc_conn.cursor()
pyodbc_cursor.execute(query)
pyodbc_results = pyodbc_cursor.fetchall()
pyodbc_conn.close()
# mssql-python query
mssql_conn = mssql_python.connect(mssql_conn_str)
mssql_cursor = mssql_conn.cursor()
mssql_cursor.execute(query)
mssql_results = mssql_cursor.fetchall()
mssql_conn.close()
# Compare
assert len(pyodbc_results) == len(mssql_results)
for p_row, m_row in zip(pyodbc_results, mssql_results):
assert tuple(p_row) == tuple(m_row)
print(f"Results match: {len(pyodbc_results)} rows")
Checklist
- [ ] Importe aktualisieren von
pyodbczumssql_python. - [ ] Entfernen Sie
DRIVER=aus den Verbindungszeichenfolgen. - [ ] Behalten Sie bestehende
?Parameterabfragen (sie funktionieren as-is). - [ ] Verwenden Sie
EXECUTEAnweisungen für gespeicherte Prozeduraufrufe. - [ ] Externe Verbindungspooling-Konfiguration entfernen.
- [ ] Aktualisieren der Klassennamen für Ausnahmebehandlung.
- [ ] Teste alle Abfragen und gespeicherten Verfahren.
- [ ] Überprüfen Sie die Verarbeitung des Datentyps (insbesondere Dezimalzahlen und Daten).
- [ ] Entfernen Sie den ODBC-Treiber aus den Einsatzanforderungen.