Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Som standard konverterar mssql-python-drivrutinen Microsoft SQL-datatyper till lämpliga Python-typer (se Datatypmappningar). Outputkonvertersystemet låter dig åsidosätta detta beteende för specifika SQL-typer, vilket aktiverar:
- Anpassade typomvandlingar (till exempel money till float i stället för Decimal)
- Integration med tredjepartsbibliotek (till exempel rumslig data till Shapely-objekt)
- Affärsspecifik formatering (till exempel datum till anpassade strängformat)
Omvandlare för registerutgångar
Använd add_output_converter() för att registrera en omvandlarfunktion. Nyckeln är antingen en Python-typ som matchar type_code i cursor.description, eller en heltalskod ODBC SQL-typ såsom 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
Välj mellan en Python-typnyckel och en SQL-typkodsnyckel
De två nyckelformerna skiljer sig åt i hur de exakt väljer kolumner:
En Python-typnyckel gäller för varje SQL-typ som mappas till den Python-typen. Att registrera en omvandlare för
Decimalomvandlar decimal-, numerisk-, penning- och småmyntskolumner .En heltals-SQL-typkodnyckel matchar ODBC-typkoden som kolumnen rapporterar, som är smalare men inte alltid en enda SQL-typ.
SQL_NUMERICtransformerar endast numeriska kolumner.SQL_DECIMALOmvandlar decimal-, money- och smallmoney-kolumnerna , eftersom alla tre rapporterar samma kod.
Använd en heltalsnyckel när en Python-typnyckel är mer generell än du vill, eller när du porterar kod från pyodbc, som använder heltalsnycklar. Använd en Python-typnyckel när du vill att en konverterare ska täcka en hel familj av SQL-typer.
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')
Upplösningsordning för omvandlare
För varje kolumn väljer drivrutinen högst en omvandlare, i denna ordning:
Omvandlaren registrerade kolumnens heltalskod för ODBC SQL-typ.
Konverteraren som är registrerad för Python-typen i
cursor.description.Konverteraren registrerades för
SQL_WVARCHAR, men endast när kolumnens Python-typ ärstrellerbytes.
Omvandlarfunktionssignatur
När du registrerar en konverterare med en Python-typnyckel måste den typ du skickar till add_output_converter() matcha en av följande Python-typer. Kolumnen Konverteraren tar emot visar vad drivrutinen skickar till din funktion:
cursor.description type_code |
Omvandlaren tar emot | Microsoft SQL-typer |
|---|---|---|
int |
int |
tinyint, smallint, int, bigint |
float |
float |
real, float |
decimal.Decimal |
Decimal |
decimal, numeric, money, smallmoney |
str |
bytes (kodad i 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
Strängtypomvandlare (strnyckel) får rå bytes i UTF-16LE-kodning, inte avkodade Python-strängar. Alla andra typer får det redan konverterade Python-objektet.
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)
Hantera omvandlare
Använd dessa metoder för att inspektera eller ta bort konverterare som redan är registrerade på en anslutning.
Skaffa befintlig omvandlare
Hämta omvandlarfunktionen som för närvarande är registrerad för en typ:
converter = conn.get_output_converter(str)
if converter:
print(f"Converter registered: {converter}")
else:
print("Using default conversion")
Ta bort en omvandlare
Avregistrera en omvandlare så att drivrutinen återgår till standardkonvertering för den typen:
conn.remove_output_converter(str)
# str columns now use default conversion
Rensa alla omvandlare
Återställ alla registrerade omvandlare till att använda Microsoft SQL:s standardtypmappningar:
conn.clear_output_converters()
# All types now use default conversion
Vanliga omvandlarmönster
Dessa exempel visar de mest frekvent behövda omvandlarfunktionerna.
Omvandla VARCHAR till versaler
Strängtypomvandlare tar emot råa bytes i UTF-16LE-kodning:
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
Konvertera pengar till flytande medel
Som standard returnerar drivrutinen typerna DECIMAL/NUMERIC som decimal.Decimal. Konvertera till 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'>
Parse JSON-data
Microsoft SQL Server kan lagra JSON som text. Automatiskt parsa till Python-objekt:
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
Detta exempel konverterar ALLA strängvärden (nvarchar, varchar, xml). JSON-parsning försöks på varje strängkolumn. I praktiken, tillämpa JSON-parsning selektivt istället för som en blanket-omvandlare.
Anpassad formatering av datum och tid
Konvertera datetime till ISO-strängformat:
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
Säkerhetsfrågor
Caution
När du registrerar en utgångsomvandlare körs funktionen du tillhandahåller på varje matchande databasvärde.
- Registrera endast konverterare från betrodd kod.
- Acceptera aldrig omvandlarfunktioner från användarens inmatning.
- Illvilliga konverterare kan köra godtycklig kod eller läcka data.
# 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)
Exempel: Integration av rumsliga data
Integrera rumslig data med Shapely-biblioteket:
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
Att registrera en bytes omvandlare påverkar ALLA binära kolumner (varbinära, geografi, geometri). Använd clear_output_converters() efter rumsliga frågor om du också frågar efter icke-rumsliga binärdata.
Exempel: Anpassad radformatering
Skapa en dataklassomvandlare:
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}")
Omvandlarens omfattning och livslängd
- Anslutningsbegränsad: Drivrutinen registrerar konverterare per anslutning, inte globalt.
- Beständig: Omvandlare förblir aktiva tills du tar bort dem eller stänger anslutningen.
- Inte ärvda: Nya anslutningar ärver inte omvandlare från andra anslutningar.
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
Prestandaöverväganden
- Drivrutinen anropar konverterare för varje värde av den registrerade typen.
- Håll omvandlarfunktionerna effektiva.
- För frågor med hög volym, överväg om konvertering är nödvändig.
- Profilera prestandan om omvandlare påverkar genomströmningen.
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