Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Domyślnie sterownik mssql-python konwertuje typy danych Microsoft SQL na odpowiednie typy Python (patrz mapowania typów danych). System konwerterów wyjściowych pozwala nadpisać to zachowanie dla konkretnych typów SQL, umożliwiając:
- Niestandardowe transformacje typów (na przykład money to float zamiast Decimal)
- Integracja z bibliotekami firm trzecich (na przykład dane przestrzenne do obiektów Shapely)
- Formatowanie specyficzne dla firmy (na przykład daty do niestandardowych formatów ciągów znaków)
Zarejestruj przetworniki wyjściowe
Użyj add_output_converter() do rejestracji funkcji konwertera. Kluczem jest albo typ w języku Python, który odpowiada elementowi cursor.description w type_code, albo całkowitoliczbowy kod typu SQL ODBC, taki jak 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
Wybierz między kluczem typu Python a kodem SQL
Dwie kluczowe formy różnią się tym, jak precyzyjnie wybierają kolumny:
Klucz typu Python jest stosowany do każdego typu SQL mapującego się na ten typ Python. Zarejestrowanie konwertera dla
Decimalprzekształca kolumny decimal, numeric, money i smallmoney.Klucz całkowitoliczbowego kodu typu SQL odpowiada kodowi typu ODBC zgłaszanemu przez kolumnę, który jest bardziej zawężony, ale nie zawsze stanowi pojedynczy typ SQL.
SQL_NUMERICprzekształca tylko kolumny liczbowe .SQL_DECIMALprzekształca kolumny decimal, money i smallmoney, ponieważ wszystkie trzy zwracają ten sam kod.
Używaj klucza całkowitoliczbowego, gdy klucz typu Python jest szerszy niż chcesz, albo gdy przenosisz kod z pyodbc, który używa kluczy całkowitoliczbowych. Używaj klucza typu Python, gdy chcesz, aby jeden konwerter pokrył całą rodzinę typów 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')
Kolejność rozdzielczości konwertera
Dla każdej kolumny sterownik wybiera co najwyżej jeden konwerter, w następującej kolejności:
Konwerter zarejestrowany dla całkowitoliczbowego kodu typu SQL ODBC kolumny.
Konwerter zarejestrowany dla typu Python w
cursor.description.Konwerter został zarejestrowany dla
SQL_WVARCHAR, ale tylko wtedy, gdy typ języka Python dla kolumny tostrlubbytes.
Sygnatura funkcji konwertera
Gdy rejestrujesz konwerter przy użyciu klucza typu Python, typ, który przekazujesz do add_output_converter(), musi być zgodny z jednym z poniższych typów języka Python. Kolumna Konwerter odbiera pokazuje, co sterownik przekazuje twojej funkcji:
cursor.description type_code |
Konwerter odbiera | Typy Microsoft SQL |
|---|---|---|
int |
int |
tinyint, smallint, int, bigint |
float |
float |
real, float |
decimal.Decimal |
Decimal |
decimal, numeric, money, smallmoney |
str |
bytes (zakodowane w UTF-16LE) |
char, varchar, , nchar, nvarcharxml |
datetime.datetime |
datetime |
datetime, datetime2, smalldatetime |
datetime.date |
date |
date |
bytes |
bytes |
varbinary, binary, geography, geometry |
bool |
bool |
bit |
Note
Konwertery typu string (strklucz) odbierają surowe bytes dane w kodowaniu UTF-16LE, a nie zdekodowane ciągi Python. Wszystkie pozostałe typy otrzymują już przekonwertowany obiekt Python.
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)
Zarządzanie konwerterami
Użyj tych metod do inspekcji lub usunięcia przetworników już zarejestrowanych na połączeniu.
Pobierz istniejący konwerter
Pobierz funkcję konwertera zarejestrowaną obecnie dla typu:
converter = conn.get_output_converter(str)
if converter:
print(f"Converter registered: {converter}")
else:
print("Using default conversion")
Usuń konwerter
Odrejestruj konwerter, aby sterownik wrócił do domyślnej konwersji dla tego typu:
conn.remove_output_converter(str)
# str columns now use default conversion
Wyczyść wszystkie konwertery
Zresetuj wszystkie zarejestrowane konwertery, aby korzystały z domyślnych mapowań typów Microsoft SQL:
conn.clear_output_converters()
# All types now use default conversion
Typowe wzory konwerterów
Te przykłady pokazują najczęściej potrzebne funkcje konwertera.
Przekonwertuj VARCHAR na wielką literę
Konwertery typu string otrzymują surowe bajty w kodowaniu 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
Przelicz pieniądze na wolne
Domyślnie sterownik zwraca typy DECIMAL/NUMERIC jako decimal.Decimal. Przelicz na 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'>
Przetwarzaj dane JSON
Microsoft SQL Server może przechowywać JSON jako tekst. Automatyczne parsowanie do obiektów 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
Ten przykład konwertuje WSZYSTKIE wartości ciągu (nvarchar, varchar, xml). Próba parsowania JSON jest wykonywana na każdej kolumnie ciągu znaków. W praktyce należy stosować parsowanie JSON selektywnie, a nie jako konwerter blanket.
Niestandardowe formatowanie czasu i daty
Przekonwertowanie czasu daty do formatu ISO string:
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
Zagadnienia dotyczące zabezpieczeń
Caution
Gdy rejestrujesz konwerter wyjściowy, funkcja, którą dostarczasz, działa na każdej odpowiadającej wartości bazy danych.
- Rejestruj tylko konwertery z zaufanego kodu.
- Nigdy nie akceptuj funkcji konwertera z danych wejściowych od użytkownika.
- Złośliwe konwertery mogą wykonywać dowolny kod lub ujawniać dane.
# 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)
Przykład: Integracja danych przestrzennych
Integruj dane przestrzenne z biblioteką 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
Rejestracja konwertera bytes wpływa na WSZYSTKIE kolumny binarne (warbinarne, geograficzne, geometryczne). Używaj clear_output_converters() po zapytaniach przestrzennych, jeśli wykonujesz również zapytania o nieprzestrzenne dane binarne.
Przykład: Niestandardowe formatowanie wierszy
Stwórz konwerter klas danych:
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}")
Zakres konwertera i czas eksploatacji
- Zakres połączeniowy: Sterownik rejestruje konwertery na każde połączenie, a nie globalnie.
- Trwałe: Konwertery pozostają aktywne, dopóki je nie usuniesz lub nie zamkniesz połączenia.
- Nie dziedziczone: Nowe połączenia nie dziedziczą konwerterów z innych połączeń.
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
Zagadnienia dotyczące wydajności
- Sterownik wywołuje konwertery dla każdej wartości zarejestrowanego typu.
- Utrzymuj efektywność funkcji konwerterów.
- W przypadku zapytań o dużej liczbie zapytań rozważ, czy konwersja jest konieczna.
- Przeprowadź profilowanie wydajności, jeśli konwertery wpływają na przepustowość.
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