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.
Di default, il driver mssql-python converte i tipi di dati Microsoft SQL in tipi Python appropriati (vedi Mappaggi dei tipi dati). Il sistema di convertitore di output ti permette di sovrascrivere questo comportamento per tipi SQL specifici, abilitando:
- Trasformazioni di tipo personalizzate (ad esempio, da money a float invece che a Decimal)
- Integrazione con librerie di terze parti (ad esempio, dati spaziali verso oggetti Shapely)
- Formattazione specifica per l'azienda (ad esempio, date a formati di stringhe personalizzate)
Convertitori per l'uscita del registro
Usalo add_output_converter() per registrare una funzione di convertimento. La chiave è un tipo di Python che corrisponde a type_code in cursor.description, oppure un codice intero del tipo SQL ODBC come mssql_python.SQL_DECIMAL:
import mssql_python
from datetime import datetime
def my_datetime_converter(value):
"""Convert datetime to a custom display string."""
if value is None:
return None
return value.strftime("%B %d, %Y at %I:%M %p")
conn = mssql_python.connect(connection_string)
conn.add_output_converter(datetime, my_datetime_converter)
cursor = conn.cursor()
cursor.execute("SELECT CAST('2026-07-16T10:30:00' AS DATETIME2)")
print(cursor.fetchval()) # July 16, 2026 at 10:30 AM
Scegli tra una chiave di tipo Python e una chiave di codice di tipo SQL
Le due forme chiave differiscono per come selezionano con precisione le colonne:
Una chiave di tipo Python si applica a ogni tipo SQL che si mappa a quel tipo Python. La registrazione di un convertitore per
Decimaltrasforma le colonne decimal, numeric, money e smallmoney.Una chiave di codice di tipo SQL intero corrisponde al codice ODBC che la colonna riporta, che è più ristretto ma non sempre è un singolo tipo SQL.
SQL_NUMERICtrasforma solo colonne numeriche .SQL_DECIMALTrasforma le colonne decimale, denaro e smallmoney , perché tutte e tre riportano lo stesso codice.
Usa una chiave intera quando una chiave di tipo Python è più ampia di quanto desideri, oppure quando porti codice da pyodbc, che usa chiavi intere. Usa una chiave di tipo Python quando vuoi che un convertitore copra un'intera famiglia di tipi SQL.
import mssql_python
def tag_decimal(value):
return f"D:{value}"
conn.add_output_converter(mssql_python.SQL_DECIMAL, tag_decimal)
cursor.execute("""
SELECT CAST(12.34 AS decimal(10,2)),
CAST(56.78 AS numeric(10,2)),
CAST(90.12 AS money)
""")
print(cursor.fetchone()) # ('D:12.34', Decimal('56.78'), 'D:90.1200')
Ordine della risoluzione del convertitore
Per ogni colonna, il driver seleziona al massimo un convertitore, in quest'ordine:
Il convertitore registrava il codice intero ODBC SQL della colonna.
È il convertitore registrato per il tipo Python in
cursor.description.Il convertitore registrava per
SQL_WVARCHAR, ma solo quando il tipo Python della colonna èstrobytes.
Firma della funzione convertitore
Quando registri un convertitore con una chiave di tipo Python, il tipo che passi a add_output_converter() deve corrispondere a uno dei seguenti tipi Python. La colonna ricevuto dal convertitore mostra quali valori il driver passa alla tua funzione:
cursor.description type_code |
Il convertitore riceve | Tipi SQL di Microsoft |
|---|---|---|
int |
int |
tinyint, smallint, intbigint |
float |
float |
real, float |
decimal.Decimal |
Decimal |
decimal, numeric, moneysmallmoney |
str |
bytes (con codifica UTF-16LE) |
char, varchar, nchar, nvarchar, xml |
datetime.datetime |
datetime |
datetime, datetime2, smalldatetime |
datetime.date |
date |
date |
bytes |
bytes |
varbinary, binary, geographygeometry |
bool |
bool |
bit |
Note
I convertitori di tipo stringa (strchiavi) ricevono il grezzo bytes nella codifica UTF-16LE, non le stringhe Python decodificate. Tutti gli altri tipi ricevono l'oggetto Python già convertito.
from decimal import Decimal
def decimal_converter(value: Decimal | None) -> float | None:
if value is None:
return None
# value is a Decimal object for numeric/money types
return float(value)
Gestire i convertitori
Usa questi metodi per ispezionare o rimuovere convertitori già registrati su una connessione.
Ottieni il convertitore esistente
Recupera la funzione convertitore attualmente registrata per un tipo:
converter = conn.get_output_converter(str)
if converter:
print(f"Converter registered: {converter}")
else:
print("Using default conversion")
Rimuovere un convertitore
Sblocca un convertitore in modo che il driver torni alla conversione predefinita per quel tipo:
conn.remove_output_converter(str)
# str columns now use default conversion
Cancella tutti i convertitori
Resetta tutti i convertitori registrati per utilizzare le mappature di tipo predefinite di Microsoft SQL:
conn.clear_output_converters()
# All types now use default conversion
Modelli di convertitore comuni
Questi esempi mostrano le funzioni di convertitore più frequentemente necessarie.
Converti VARCHAR in maiuscolo
I convertitori di tipo stringa ricevono byte grezzi nella codifica UTF-16LE:
def uppercase_converter(value):
if value is None:
return None
return value.decode('utf-16-le').upper()
conn.add_output_converter(str, uppercase_converter)
cursor = conn.cursor()
cursor.execute("SELECT 'hello world'")
print(cursor.fetchval()) # HELLO WORLD
Converti il denaro in float
Di default, il driver restituisce i tipi DECIMAL/NUMERIC come decimal.Decimal. Converti in float:
from decimal import Decimal
def money_to_float(value):
if value is None:
return None
return float(value)
conn.add_output_converter(Decimal, money_to_float)
cursor = conn.cursor()
cursor.execute("SELECT CAST(19.99 AS MONEY)")
result = cursor.fetchval()
print(type(result)) # <class 'float'>
Analizza i dati JSON
Microsoft SQL Server può memorizzare JSON come testo. Conversione automatica in oggetti Python:
import json
def json_converter(value):
if value is None:
return None
text = value.decode('utf-16-le')
try:
return json.loads(text)
except json.JSONDecodeError:
return text # Return as string if not valid JSON
conn.add_output_converter(str, json_converter)
cursor = conn.cursor()
cursor.execute("SELECT '{\"name\": \"Widget\", \"price\": 19.99}'")
data = cursor.fetchval()
print(data['name']) # Widget
Attenzione
Questo esempio converte TUTTI i valori delle stringhe (nvarchar, varchar, xml). Si tenta l'analisi JSON su ogni colonna di stringhe. In pratica, applica l'analisi JSON in modo selettivo invece che come convertitore a copertura.
Formattazione personalizzata con data-orario
Converti data e ora in formato stringa ISO:
from datetime import datetime
def datetime_to_iso(value):
if value is None:
return None
return value.isoformat()
conn.add_output_converter(datetime, datetime_to_iso)
cursor = conn.cursor()
cursor.execute("SELECT TOP 1 ModifiedDate FROM Production.Product")
print(cursor.fetchval()) # 2014-02-08T10:01:36.827000
Considerazioni relative alla sicurezza
Attenzione
Quando registri un convertitore di output, la funzione che fornisci viene eseguita su ogni valore corrispondente del database.
- Registra solo i convertitori da codice affidabile.
- Non accettare mai le funzioni del convertitore tramite input dell'utente.
- I convertitori dannosi potrebbero eseguire codice arbitrario o far fuggire dati.
# DANGEROUS - never do this
def unsafe_example(user_converter_code):
converter_func = eval(user_converter_code) # Security risk!
conn.add_output_converter(str, converter_func)
Esempio: Integrazione dei dati spaziali
Integra i dati spaziali con la libreria Shapely:
from shapely import wkb
def geometry_converter(value):
"""Convert WKB binary to Shapely geometry object."""
if value is None:
return None
return wkb.loads(value)
conn.add_output_converter(bytes, geometry_converter)
# Query must use STAsBinary() to get standard WKB format
cursor = conn.cursor()
cursor.execute(
"SELECT SpatialLocation.STAsBinary() FROM Person.Address "
"WHERE SpatialLocation IS NOT NULL AND City = 'Seattle'"
)
for row in cursor:
shape = row[0]
print(f"Point: ({shape.x:.4f}, {shape.y:.4f})")
Note
La registrazione di un bytes convertitore riguarda TUTTE le colonne binarie (varbinaria, geografia, geometria). Usa clear_output_converters() dopo le query spaziali se interroghi anche dati binari non spaziali.
Esempio: Formattazione personalizzata delle righe
Crea un convertitore di classi dati:
from dataclasses import dataclass
@dataclass
class Product:
id: int
name: str
price: float
def fetch_products_as_dataclass(cursor):
"""Convert rows to Product dataclass instances."""
cursor.execute(
"SELECT ProductID, Name, ListPrice FROM Production.Product "
"WHERE ListPrice > 0"
)
results = []
for row in cursor:
results.append(Product(
id=row.ProductID,
name=row.Name,
price=float(row.ListPrice)
))
return results
products = fetch_products_as_dataclass(cursor)
for p in products[:5]:
print(f"{p.name}: ${p.price:.2f}")
Scopo del convertitore e durata del convertitore
- Con ambito di connessione: Il driver registra i convertitori per ogni connessione, non a livello globale.
- Persistente: I convertitori rimangono attivi finché non li rimuovi o chiudi la connessione.
- Non ereditato: le nuove connessioni non ereditano convertitori da altre connessioni.
conn1 = mssql_python.connect(connection_string)
conn1.add_output_converter(str, uppercase_converter)
conn2 = mssql_python.connect(connection_string)
# conn2 does NOT have the converter registered
Considerazioni sulle prestazioni
- Il driver chiama i convertitori per ogni valore del tipo registrato.
- Mantieni le funzioni del convertitore efficienti.
- Per le query ad alto volume, valuta se la conversione sia necessaria.
- Analizza le prestazioni se i convertitori influiscono sulla velocità effettiva.
import time
def slow_converter(value):
time.sleep(1) # Avoid time consuming routines like this - adds 1 second for each value processed!
return str(value) if value else None