Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il driver mssql-python è il driver Python di prima parte di Microsoft per Microsoft SQL. Se preferisci un'opzione driver mantenuta da Microsoft, offre:
- Nessuna dipendenza da driver ODBC esterni.
- Pooling di connessione integrato.
- Supporto moderno per Python 3.10+.
- Autenticazione nativa Microsoft Entra.
Differenze principali
| Feature | pyodbc | mssql-python |
|---|---|---|
| Stile dei parametri |
qmark (?) |
qmark (?) e pyformat (%(name)s) |
| Driver ODBC è richiesto | Sì | No |
| Pool di connessioni | Esterno | Predefinito |
| Versione minima di Python | 3.6 | 3.10 |
callproc() |
Supportato | Non implementato |
| Autocommit predefinito | Off | Off |
Passaggi base della migrazione
I passaggi seguenti coprono le modifiche chiave per migrare un'applicazione pyodbc su mssql-python.
1. Aggiornare le importazioni
Sostituisci l'importazione pyodbc con mssql_python:
Prima (pyodbc):
import pyodbc
Dopo (mssql-python):
import mssql_python
2. Aggiornare stringhe di connessione
Rimuovi la DRIVER= parola chiave e aggiorna il metodo di autenticazione:
In precedenza (pyodbc, richiede il driver ODBC):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
Dopo (mssql-python, nessun driver necessario, usando l'autenticazione di Microsoft Entra):
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
3. Mantieni le tue query così come sono
Il driver mssql-python supporta entrambi gli stili di parametri ? (qmark) e %(name)s (pyformat). Le tue query esistenti ? funzionano senza cambiamenti:
Prima (pyodbc):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
Dopo (mssql-python, la stessa query):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
4. Mantieni executemany così com'è
Le chiamate esistenti executemany con tuple e ? marker funzionano senza modifiche:
Prima (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)
Dopo (mssql-python, stesso codice):
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)
Migrazione delle procedure memorizzate
Il driver mssql-python non implementa callproc(). Le sezioni seguenti mostrano come usarlo EXECUTE invece.
Usa EXECUTE per le stored procedure
Il driver pyodbc supporta callproc(), ma il driver mssql-python no. Usare EXECUTE invece:
Prima (pyodbc):
cursor.callproc("dbo.uspGetEmployeeManagers", (5,))
results = cursor.fetchall()
Dopo (mssql-python):
cursor.execute(
"EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s",
{"id": 5}
)
results = cursor.fetchall()
print(f"Got {len(results)} rows")
Parametri di output
Usa variabili T-SQL per catturare i valori di output invece di affidarti ai callproc() parametri di output:
Prima (pyodbc, usando callproc):
params = (category_id, pyodbc.SQL_INTEGER)
cursor.callproc("dbo.GetProductCount", params)
count = params[1].value
Dopo (mssql-python, usando variabili T-SQL):
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}")
Migrazioni specifiche per funzionalità
Le sezioni seguenti trattano specifiche caratteristiche pyodbc e i loro equivalenti mssql-python.
Stringhe di connessione
| Parola chiave pyodbc | parola chiave mssql-python | Notes |
|---|---|---|
DRIVER={...} |
Non necessario | Il driver ODBC è integrato internamente. |
SERVER= |
Server= |
Nessuna modifica del comportamento. |
DATABASE= |
Database= |
Nessuna modifica del comportamento. |
Trusted_Connection= |
Trusted_Connection= |
Nessuna modifica del comportamento. |
UID= / PWD= |
UID= / PWD= |
Nessuna modifica del comportamento. |
Authentication= |
Authentication= |
Accetta gli stessi valori. |
Autocommit
Il comportamento dell'autocommit è identico in entrambi i driver:
pyodbc:
conn.autocommit = True
pyodbc.connect(connection_string, autocommit=True)
MSSQL-Python:
conn.autocommit = True
Inserimenti in blocco
Per velocizzare i batch di grandi dimensioni INSERT, gli utenti di pyodbc impostano fast_executemany = True. Il driver mssql-python ottimizza executemany già per i batch parametrizzati, quindi inserti moderati non hanno bisogno di flag speciale. Per carichi di dati elevati, preferisci bulkcopy(), che trasmette le righe tramite il protocollo di copia in massa ed è molto più veloce rispetto all'emissione di singole INSERT sentenzioni. Per il flusso di lavoro completo, vedi Usa copia in massa.
pyodbc:
cursor.fast_executemany = True
cursor.executemany(query, data)
Dopo (mssql-python), batch di dimensioni moderate con 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()
Dopo (mssql-python), carichi grandi con bulkcopy (preferibile):
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()
Factory di righe
Il driver mssql-python restituisce Row oggetti che supportano l'accesso agli attributi di default, senza richiedere una custom row factory:
PYODBC (fabbrica di file personalizzate):
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 (accesso agli attributi di default):
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
Gestione degli errori
Il driver mssql-python utilizza la stessa gerarchia delle eccezioni di pyodbc, quindi la maggior parte dei gestori di eccezioni richiede solo un cambio di nome del modulo.
Gerarchia delle eccezioni
I nomi delle classi di eccezione corrispondono direttamente da un driver all'altro:
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
Dettagli dell'errore
Entrambi i driver espongono i dettagli dell'errore tramite gli argomenti dell'eccezione:
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))
Pool di connessioni
Il driver mssql-python include di default il pool di connessioni, quindi non sono più necessarie librerie di pooling esterne.
Rimuovere il pool esterno
Se hai usato il pool esterno con pyodbc, il driver mssql-python lo ha integrato:
Prima (pool esterno di pyodbc):
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()
Dopo (pooling integrato di mssql-python):
conn = mssql_python.connect(connection_string)
conn.close()
Configura il pool
Sostituisci la dimensione predefinita del pool e il timeout con mssql_python.pooling():
import mssql_python
mssql_python.pooling()
Esempio di migrazione completa
Quanto segue mostra la stessa funzione scritta con pyodbc e poi riscritta con mssql-python.
Prima (pyodbc)
Questa versione utilizza la stringa di connessione pyodbc con una DRIVER parola chiave:
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
Dopo (mssql-python)
Questa versione elimina la DRIVER parola chiave. Tutte le query, i parametri e i modelli di accesso alle righe rimangono identici:
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
Le uniche modifiche sono l'istruzione import e la stringa di connessione (non è necessaria la parola chiave DRIVER). Ogni query, parametro, pattern di fetch e accesso alla riga rimane identico.
Verifica della migrazione
Prima di completare la migrazione, esegui le stesse query su entrambi i driver e confronta i risultati per confermare il comportamento equivalente.
Verifica il comportamento equivalente
Usa una funzione di confronto che esegue la stessa query su entrambi i driver e afferma che i risultati corrispondono:
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
- [ ] Aggiorna le importazioni da
pyodbcamssql_python. - [ ] Rimuovi
DRIVER=dalle stringhe di connessione. - [ ] Conserva le query dei parametri esistenti
?(funzionano as-is). - [ ] Usa le istruzioni
EXECUTEper chiamare le stored procedure. - [ ] Rimuovere la configurazione del pool di connessione esterna.
- [ ] Aggiornare i nomi delle classi di gestione delle eccezioni.
- [ ] Testa tutte le query e le procedure memorizzate.
- [ ] Verifica la gestione dei tipi di dati (specialmente decimali e date).
- [ ] Rimuovere il driver ODBC dai requisiti di implementazione.