Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Par défaut, le pilote mssql-python convertit les types de données SQL de Microsoft en types Python correspondants (voir Correspondance des types de données). Le système de conversion de sortie vous permet de remplacer ce comportement pour des types SQL spécifiques, en permettant :
- Transformations de types personnalisées (par exemple, de money en float au lieu de Decimal)
- Intégration avec des bibliothèques tierces (par exemple, données spatiales vers des objets Shapely)
- Formatage spécifique à l’entreprise (par exemple, conversion des dates en formats de chaîne personnalisés)
Enregistrer des convertisseurs de sortie
Utilisez add_output_converter() pour enregistrer une fonction de convertisseur. La clé est soit un type Python correspondant à type_code dans cursor.description, soit un code entier ODBC SQL tel que 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
Choisissez entre une clé de type Python et une clé de code de type SQL
Les deux formes clés diffèrent dans la précision de la sélection des colonnes :
Une clé de type Python s’applique à chaque type SQL qui correspond à ce type Python. L’enregistrement d’un convertisseur pour
Decimaltransforme les colonnes decimal, numeric, money et smallmoney.Une clé de code de type SQL entier correspond au code ODBC que la colonne rapporte, qui est plus étroit mais n’est pas toujours un seul type SQL.
SQL_NUMERICne transforme que les colonnes numériques .SQL_DECIMALtransforme les colonnes decimal, money et smallmoney, car toutes les trois renvoient ce même code.
Utilisez une clé d'entières lorsqu'une clé de type Python est plus large que ce que vous souhaitez, ou lorsque vous portez du code depuis pyodbc, qui utilise des clés d'entiers. Utilisez une clé de type Python lorsque vous voulez qu’un convertisseur couvre toute une famille de types 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')
Ordre de résolution du convertisseur
Pour chaque colonne, le pilote sélectionne au maximum un convertisseur, dans cet ordre :
Le convertisseur s’est enregistré pour le code entier type ODBC SQL de la colonne.
Le convertisseur a été enregistré pour le type Python dans
cursor.description.Le convertisseur s'est enregistré pour
SQL_WVARCHAR, mais seulement lorsque le type Python de la colonne eststroubytes.
Signature d’une fonction de conversion
Lorsque vous enregistrez un convertisseur avec une clé de type Python, le type que vous passez à add_output_converter() doit correspondre à l’un des types Python suivants. La colonne Valeur reçue par le convertisseur indique ce que le pilote transmet à votre fonction :
cursor.description type_code |
Le convertisseur reçoit | Types SQL de Microsoft |
|---|---|---|
int |
int |
tinyint, smallint, int, bigint |
float |
float |
real, float |
decimal.Decimal |
Decimal |
decimal, numeric, money, smallmoney |
str |
bytes (encodé en UTF-16LE) |
char, varchar, nchar, nvarchar, xml |
datetime.datetime |
datetime |
datetime, datetime2, smalldatetime |
datetime.date |
date |
date |
bytes |
bytes |
varbinary, binary, geography, geometry |
bool |
bool |
bit |
Note
Les convertisseurs de type chaîne (strkey) reçoivent des chaînes brutes bytes en codage UTF-16LE, et non des chaînes Python décodées. Tous les autres types reçoivent l’objet Python déjà converti.
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)
Gérer les convertisseurs
Utilisez ces méthodes pour inspecter ou retirer les convertisseurs déjà enregistrés sur une connexion.
Obtenir le convertisseur existant
Récupérer la fonction de convertisseur actuellement enregistrée pour un type :
converter = conn.get_output_converter(str)
if converter:
print(f"Converter registered: {converter}")
else:
print("Using default conversion")
Retirez un convertisseur
Désenregistrer un convertisseur pour que le pilote revienne à la conversion par défaut pour ce type :
conn.remove_output_converter(str)
# str columns now use default conversion
Effacer tous les convertisseurs
Réinitialisez tous les convertisseurs enregistrés pour utiliser les correspondances de type par défaut de Microsoft SQL :
conn.clear_output_converters()
# All types now use default conversion
Patrons de convertisseur courants
Ces exemples montrent les fonctions de convertisseur les plus fréquemment nécessaires.
Convertir VARCHAR en majuscules
Les convertisseurs de type chaîne reçoivent des octets bruts en codage 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
Convertir de money en float
Par défaut, le pilote retourne les types DÉCIMAUX/NUMÉRIQUES comme decimal.Decimal. Convertir en 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'>
Analyser les données JSON
Microsoft SQL Server peut stocker du JSON sous forme de texte. Analyse automatique en objets 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
Caution
Cet exemple convertit TOUTES les valeurs de chaînes (nvarchar, varchar, xml). L’analyse JSON est tentée sur chaque colonne de chaînes. En pratique, appliquez l’analyse JSON de manière sélective plutôt que comme un convertisseur global.
Formatage personnalisé de la date et de l’heure
Convertir la date et l’heure au format de chaîne 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
Considérations relatives à la sécurité
Caution
Lorsque vous enregistrez un convertisseur de sortie, la fonction que vous fournissez s’exécute sur chaque valeur correspondante de la base de données.
- N’enregistrez que des convertisseurs provenant d’un code fiable.
- N’acceptez jamais de fonctions de conversion provenant des entrées utilisateur.
- Les convertisseurs malveillants pouvaient exécuter un code arbitraire ou faire fuir des données.
# 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)
Exemple : Intégration des données spatiales
Intégrez les données spatiales avec la bibliothèque 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
L’enregistrement d’un bytes convertisseur affecte TOUTES les colonnes binaires (varbinaire, géographie, géométrie). Utilisez clear_output_converters() après des requêtes spatiales si vous effectuez également des requêtes sur des données binaires non spatiales.
Exemple : formatage de lignes personnalisé
Créez un convertisseur de classes de données :
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}")
Portée du convertisseur et durée de vie
- Étendu à la connexion : le pilote enregistre les convertisseurs par connexion, pas globalement.
- Persistant : Les convertisseurs restent actifs jusqu’à ce que vous les retiriez ou fermiez la connexion.
- Non hérités : Les nouvelles connexions n’héritent pas des convertisseurs d’autres connexions.
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
Considérations relatives aux performances
- Le conducteur appelle des convertisseurs pour chaque valeur du type enregistré.
- Gardez les fonctions du convertisseur efficaces.
- Pour les requêtes à grand volume, considérez si la conversion est nécessaire.
- Analysez les performances si les convertisseurs ont une incidence sur le débit.
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