Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Por defeito, o driver mssql-python converte tipos de dados Microsoft SQL em tipos Python apropriados (ver Mapeamentos de tipos de dados). O sistema de conversor de saída permite-lhe sobrepor este comportamento para tipos SQL específicos, possibilitando:
- Transformações de tipos personalizadas (por exemplo, dinheiro para flutuar em vez de Decimal)
- Integração com bibliotecas de terceiros (por exemplo, dados espaciais para objetos Shapely)
- Formatação específica da empresa (por exemplo, datas em formatos personalizados de cadeias de caracteres)
Conversores de saída de registadores
Use add_output_converter() para registar uma função de conversor. A chave é ou um tipo Python que corresponde ao type_code em cursor.description, ou um código inteiro ODBC SQL, como 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
Escolha entre uma chave de tipo Python e uma chave de código de tipo SQL
As duas formas-chave diferem na precisão como selecionam as colunas:
Uma chave de tipo Python aplica-se a cada tipo SQL que corresponde a esse tipo Python. O registo de um conversor para
Decimaltransforma as colunas decimal, numeric, money e smallmoney.Uma chave de código de tipo SQL inteiro corresponde ao código ODBC que a coluna reporta, que é mais estreita mas nem sempre é um único tipo SQL.
SQL_NUMERICtransforma apenas colunas numéricas .SQL_DECIMALtransforma as colunas decimal, dinheiro e smallmoney , porque as três reportam esse mesmo código.
Usa uma chave inteira quando uma chave do tipo Python for mais ampla do que gostarias, ou quando estiveres a portar código do pyodbc, que usa chaves inteiras. Usa uma chave de tipo Python quando quiseres que um conversor cubra toda uma família de tipos 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')
Ordem de resolução do conversor
Para cada coluna, o driver seleciona no máximo um conversor, nesta ordem:
O conversor foi registado para o código de tipo SQL ODBC inteiro da coluna.
O conversor foi registado para o tipo Python em
cursor.description.O conversor registou-se para
SQL_WVARCHAR, mas apenas quando o tipo Python da coluna éstroubytes.
Assinatura de função conversora
Quando regista um conversor com uma chave de tipo do Python, o tipo que passa a add_output_converter() tem de corresponder a um dos seguintes tipos do Python. A coluna O conversor recebe mostra o que o controlador passa à sua função:
cursor.description type_code |
O conversor recebe | Tipos SQL da Microsoft |
|---|---|---|
int |
int |
tinyint, smallint, int, bigint |
float |
float |
real, float |
decimal.Decimal |
Decimal |
decimal, numeric, money, smallmoney |
str |
bytes (codificado em 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
Conversores do tipo string (str chave) recebem os dados bytes em bruto com codificação UTF-16LE, e não cadeias de caracteres de Python descodificadas. Todos os outros tipos recebem o objeto Python já convertido.
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)
Gerir conversores
Use estes métodos para inspecionar ou remover conversores já registados numa ligação.
Obter conversor existente
Recuperar a função conversora atualmente registada para um tipo:
converter = conn.get_output_converter(str)
if converter:
print(f"Converter registered: {converter}")
else:
print("Using default conversion")
Remova um conversor
Anular o registo de um conversor para que o controlador retome a conversão predefinida para esse tipo:
conn.remove_output_converter(str)
# str columns now use default conversion
Limpar todos os conversores
Reiniciar todos os conversores registados para usar os mapeamentos de tipos predefinidos do Microsoft SQL:
conn.clear_output_converters()
# All types now use default conversion
Padrões comuns de conversores
Estes exemplos mostram as funções de conversor mais frequentemente necessárias.
Converta VARCHAR em maiúsculas
Conversores do tipo string recebem bytes brutos na codificação 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
Converter dinheiro em float
Por predefinição, o controlador devolve os tipos DECIMAL/NUMERIC como decimal.Decimal. Converter para 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'>
Analisar dados JSON
O Microsoft SQL Server pode armazenar JSON como texto. Análise automática para objetos 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
Atenção
Este exemplo converte TODOS os valores das cadeias (nvarchar, varchar, xml). A análise sintática JSON é tentada em todas as colunas de strings. Na prática, aplique a análise de JSON seletivamente, em vez de a usar como um conversor genérico.
Formatação personalizada de data e hora
Converter data e hora para o formato de cadeia 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
Considerações de segurança
Atenção
Quando regista um conversor de saída, a função que fornece executa-se em todos os valores correspondentes da base de dados.
- Regista apenas conversores de código confiável.
- Nunca aceite funções de conversor a partir de entradas do utilizador.
- Conversores maliciosos podiam executar código arbitrário ou vazar dados.
# 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)
Exemplo: Integração de dados espaciais
Integre dados espaciais com a biblioteca 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
Registar um bytes conversor afeta TODAS as colunas binárias (varbinária, geografia, geometria). Utilize clear_output_converters() após consultas espaciais se também consultar dados binários não espaciais.
Exemplo: Formatação de linha personalizada
Crie um conversor de classes de dados:
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}")
Âmbito e tempo de vida do conversor
- Escopo de conexão: O driver regista conversores por ligação, não globalmente.
- Persistente: Os conversores permanecem ativos até os remover ou fechar a ligação.
- Não herdadas: Novas ligações não herdam conversores de outras ligações.
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
Considerações sobre desempenho
- O controlador invoca conversores para cada valor do tipo registado.
- Mantenha as funções do conversor eficientes.
- Para consultas de grande volume, considere se a conversão é necessária.
- Desempenho do perfil se os conversores afetam o rendimento.
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