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.
Standardmäßig wandelt der mssql-python-Treiber Microsoft SQL-Datentypen in geeignete Python-Typen um (siehe Datentypabbildungen). Das Output-Konvertersystem erlaubt es, dieses Verhalten für bestimmte SQL-Typen zu überschreiben und so Folgendes zu aktivieren:
- Benutzerdefinierte Typtransformationen (zum Beispiel von money zu float statt zu Decimal)
- Integration mit Drittanbieter-Bibliotheken (zum Beispiel räumliche Daten zu Shapely-Objekten)
- Unternehmensspezifische Formatierung (zum Beispiel Datumsangaben in benutzerdefinierte Zeichenfolgenformate)
Ausgangswandler registrieren
Verwenden Sie add_output_converter(), um eine Konvertierungsfunktion zu registrieren. Der Schlüssel ist entweder ein Python-Typ, der mit dem type_code in cursor.descriptionübereinstimmt, oder ein ganzzahliger ODBC-SQL-Code wie 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
Wählen Sie zwischen einem Python-Typschlüssel und einem SQL-Codeschlüssel
Die beiden Schlüsselformen unterscheiden sich darin, wie genau sie Spalten auswählen:
Ein Schlüssel eines Python-Typs gilt für jeden SQL-Typ, der diesem Python-Typ zugeordnet ist. Das Registrieren eines Konverters für
Decimalkonvertiert decimal-, numeric-, money- und smallmoney-Spalten.Ein Schlüssel vom SQL-Typcode Integer entspricht dem ODBC-Typcode, den die Spalte meldet, der spezifischer ist, jedoch nicht immer einem einzelnen SQL-Typ entspricht.
SQL_NUMERICtransformiert nur numerische Spalten.SQL_DECIMALEs transformiert Dezimal-, Geld- und Kleingeld-Spalten , weil alle drei denselben Code angeben.
Verwende einen Integer-Schlüssel, wenn ein Python-Schlüssel breiter ist als du möchtest, oder wenn du Code von Pyodbc portierst, das Integer-Schlüssel verwendet. Verwende einen Python-Typschlüssel, wenn du einen Konverter für eine ganze Familie von SQL-Typen verwenden möchtest.
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')
Auflösungsreihenfolge des Konverters
Für jede Spalte wählt der Treiber höchstens einen Konverter aus, in folgender Reihenfolge:
Der Konverter registrierte sich für den ganzzahligen ODBC-SQL-Typcode der Spalte.
Der für den Python-Typ in
cursor.descriptionregistrierte Konverter.Der Konverter wurde für
SQL_WVARCHARregistriert, aber nur, wenn der Python-Typ der Spaltebytesoderstrist.
Funktionssignatur des Konverters
Wenn Sie einen Konverter mit einem Python-Typschlüssel registrieren, muss der Typ, den Sie an add_output_converter() übergeben, einem der folgenden Python-Typen entsprechen. Die Spalte Konverterempfänger zeigt an, was der Treiber an Ihre Funktion übergibt:
cursor.description type_code |
Konverter empfängt | Microsoft SQL-Typen |
|---|---|---|
int |
int |
tinyint, smallint, int, bigint |
float |
float |
real, float |
decimal.Decimal |
Decimal |
decimal, numeric, money, smallmoney |
str |
bytes (UTF-16LE kodiert) |
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
Konverter vom Typ String (str key) erhalten rohe bytes-Werte in UTF-16LE-Kodierung, nicht dekodierte Python-Strings. Alle anderen Typen erhalten das bereits konvertierte Python-Objekt.
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)
Konverter verwalten
Verwenden Sie diese Methoden, um bereits registrierte Konverter in einer Verbindung zu inspizieren oder zu entfernen.
Holen Sie sich einen bestehenden Konverter
Holen Sie die derzeit für einen Typ registrierte Konverterfunktion ab:
converter = conn.get_output_converter(str)
if converter:
print(f"Converter registered: {converter}")
else:
print("Using default conversion")
Entfernen Sie einen Konverter
Einen Konverter deregistrieren, damit der Treiber für diesen Typ zur Standardumwandlung zurückkehrt:
conn.remove_output_converter(str)
# str columns now use default conversion
Alle Konverter löschen
Setze alle registrierten Konverter zurück, um die Standardtypzuordnungen von Microsoft SQL zu verwenden:
conn.clear_output_converters()
# All types now use default conversion
Gängige Konvertierungsmuster
Diese Beispiele zeigen die am häufigsten benötigten Wandlerfunktionen.
VARCHAR in Großbuchstaben umwandeln
Konverter vom Typ String erhalten Rohbytes in UTF-16LE-Kodierung:
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
money zu float konvertieren
Standardmäßig gibt der Treiber die DECIMAL-/NUMERIC-Typen als zurück decimal.Decimal. In Float konvertieren:
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'>
JSON-Daten analysieren
Microsoft SQL Server kann JSON als Text speichern. Automatisch zu Python-Objekten parsen:
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
Dieses Beispiel konvertiert ALLE String-Werte (nvarchar, varchar, xml). JSON-Parsing wird bei jeder Zeichenkettenspalte versucht. In der Praxis wenden Sie JSON-Parsing selektiv an, anstatt als Blanket-Konverter.
Benutzerdefinierte Datetime-Formatierung
Date-Time in das ISO-String-Format umwandeln:
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
Sicherheitsüberlegungen
Caution
Wenn du einen Ausgabekonverter registrierst, läuft die von dir bereitgestellte Funktion auf jedem passenden Datenbankwert.
- Registrieren Sie nur Konverter aus vertrauenswürdigem Code.
- Akzeptieren Sie niemals Konverterfunktionen aus Benutzereingaben.
- Bösartige Konverter könnten beliebigen Code ausführen oder Daten durchsickern.
# 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)
Beispiel: Integration räumlicher Daten
Integrieren Sie räumliche Daten in die Shapely-Bibliothek:
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
Die Registrierung eines Konverters bytes beeinflusst ALLE Binärspalten (varibinär, geografisch, geometrisch). Verwenden Sie clear_output_converters() nach räumlichen Abfragen, wenn Sie auch nicht räumliche Binärdaten abfragen.
Beispiel: Benutzerdefinierte Zeilenformatierung
Erstellen Sie einen Datenklassenkonverter:
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}")
Umfang und Lebensdauer des Konverters
- Verbindungsbezogen: Der Treiber registriert Konverter pro Verbindung, nicht global.
- Persistent: Konverter bleiben aktiv, bis du sie entfernst oder die Verbindung schließt.
- Nicht geerbt: Neue Verbindungen übernehmen keine Konverter von anderen Verbindungen.
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
Leistungsüberlegungen
- Der Treiber ruft für jeden Wert des registrierten Typs Konverter auf.
- Halte die Wandlerfunktionen effizient.
- Für Anfragen mit hohem Volumen überlegen Sie, ob eine Konvertierung notwendig ist.
- Profilleistung, wenn Konverter den Durchsatz beeinflussen.
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