Mapeamentos de tipos de dados para mssql-python

O driver mssql-python mapeia automaticamente tipos de dados Python para tipos SQL Server ao enviar parâmetros e converte tipos SQL Server para tipos Python ao recuperar resultados.

Mapeamentos de Python para SQL Server

Quando passa valores Python como parâmetros para execute() ou executemany(), o driver seleciona automaticamente o tipo de SQL Server apropriado. Para a maioria das aplicações, o mapeamento automático está correto. Use setinputsizes() (descrito mais adiante neste artigo) apenas quando precisar de sobrescrever o padrão, por exemplo para forçar varchar em vez de nvarchar ou para controlar metadados de parâmetros para entradas de string e inteiros.

Tipo Python Tipo de SQL Server Notes
None NULL SQL NULL value.
bool bit True→1, False→0.
int tinyint, smallint, int,bigint Tamanho selecionado com base na gama de valores.
float float Ponto flutuante de 64 bits.
decimal.Decimal decimal, numérico Preserva a precisão até 38 dígitos.
str Varchar, Nvarchar Usa nvarchar para conteúdo Unicode.
bytes, bytearray varbinary Dados binários.
datetime.date date Só para o encontro.
datetime.time time Só o tempo.
datetime.datetime datetime2 Data e hora com precisão em nanossegundos.
uuid.UUID uniqueidentifier GUID de 16 bytes.

Seleção de tipos inteiros

O driver seleciona automaticamente o menor tipo inteiro que pode conter o valor:

Intervalo de valores Tipo de SQL Server
0 a 255 tinyint
-32.768 a 32.767 smallint
-2.147.483.648 a 2.147.483.647 int
Valores maiores bigint

Tipos de grande valor

Para strings e dados binários que excedam os limites padrão, o driver usa automaticamente os tipos MAX:

Condição Tipo de SQL Server
String > 8.000 bytes (varchar) varchar(max)
String > 4.000 caracteres (nvarchar) nvarchar(max)
Binário > de 8.000 bytes varbinary(max)

O driver transmite valores elevados para o servidor para minimizar o uso de memória.

Mapeamentos de SQL Server para Python

Quando o driver recupera dados do SQL Server, converte valores para tipos Python:

Tipo de SQL Server Tipo Python Notes
bit bool Verdadeiro/Falso.
tinyint, smallint, int,bigint int Python inteiro (precisão arbitrária).
real float Ponto flutuante de 32 bits.
float float Ponto flutuante de 64 bits.
decimal, numérico decimal.Decimal Preserva a precisão.
dinheiro, dinheiro pequeno decimal.Decimal Precisão fixa (quatro casas decimais).
Char, Varchar, Texto str Descodificado como UTF-8.
nchar, nvarchar, ntext str Decodificado como UTF-16LE.
binário, varbinário, imagem bytes Binário bruto.
date datetime.date Só para o encontro.
time datetime.time Tempo com precisão de microssegundos.
Hora do encontro, PequenoEncontroHora datetime.datetime Tipos de datas legadas.
datetime2 datetime.datetime Hora de encontro de alta precisão.
datetimeoffset datetime.datetime Data-hora com base no fuso horário.
uniqueidentifier uuid.UUID Objetos UUID em Python.
xml str XML como texto.
Geografia, geometria bytes Tipos espaciais como binários.
hierarchyid bytes Dados da hierarquia como binários.
sql_variant Variações Resolvido para o tipo base subjacente. sql_variant As colunas usam um caminho de busca em streaming, que pode ter um ligeiro impacto no desempenho em comparação com colunas do tipo fixo.
NULL None Python Nenhum.

Constantes de tipo SQL

O driver exporta constantes que correspondem a identificadores de tipo SQL ODBC. Normalmente usas estas constantes para setinputsizes() sobrepor a inferência de tipo padrão do driver quando o mapeamento automático não corresponde ao teu esquema.

Tipos de personagens

Constante Valor Descrição
SQL_CHAR 1 Carácter ANSI de comprimento fixo.
SQL_VARCHAR 12 Carácter ANSI de comprimento variável.
SQL_LONGVARCHAR -1 ANSI longo de comprimento variável.
SQL_WCHAR -8 Unicode de comprimento fixo.
SQL_WVARCHAR -9 Unicode de comprimento variável.
SQL_WLONGVARCHAR -10 Unicode longo de comprimento variável.

Tipos numéricos

Constante Valor Descrição
SQL_BIT -7 Bit/booleano.
SQL_TINYINT -6 Inteiro não assinado de 8 bits.
SQL_SMALLINT 5 Inteiro assinado de 16 bits.
SQL_INTEGER 4 Inteiro assinado de 32 bits.
SQL_BIGINT 5- Inteiro assinado de 64 bits.
SQL_REAL 7 Ponto flutuante de 32 bits.
SQL_FLOAT 6 Ponto flutuante de 64 bits.
SQL_DOUBLE 8 Ponto flutuante de 64 bits.
SQL_DECIMAL 3 Decimal de precisão fixa.
SQL_NUMERIC 2 Numérico de precisão fixa.

Tipos de data e hora

Constante Valor Descrição
SQL_TYPE_DATE 91 Só para o encontro.
SQL_TYPE_TIME 92 Só o tempo.
SQL_TYPE_TIMESTAMP 93 Data e hora.
SQL_SS_TIME2 -154 SQL Server tempo(n).
SQL_DATETIMEOFFSET -155 SQL Server datetimeoffset.

Note

SQL_SS_TIME2 e SQL_DATETIMEOFFSET são constantes internas que não são exportadas como atributos ao nível do módulo. Use os valores inteiros (-154, -155) diretamente ao chamar add_output_converter().

Tipos binários

Constante Valor Descrição
SQL_BINARY -2 Binário de comprimento fixo.
SQL_VARBINARY -3 Binário de comprimento variável.
SQL_LONGVARBINARY -4 Binário longo de comprimento variável.

Outros tipos

Constante Valor Descrição
SQL_GUID -11 Identificador único.
SQL_XML -152 Dados XML.
SQL_SS_UDT -151 Tipo definido pelo utilizador (espacial).
SQL_SS_VARIANT -150 sql_variant dados.

Note

SQL_SS_UDT e SQL_SS_VARIANT são constantes internas que não são exportadas como atributos ao nível do módulo. Use os valores inteiros (-151, -150) diretamente ao chamar add_output_converter().

Use setinputsizes()

Chame setinputsizes() antes executemany() para declarar explicitamente os tipos de parâmetros quando a inferência automática de tipos do driver causa comportamentos inesperados, por exemplo, quando uma coluna é varchar(100) mas o driver envia nvarchar:

Note

Para valores decimais, baseia-se na inferência automática de tipos do condutor em vez de SQL_DECIMAL ou SQL_NUMERIC. Essas constantes decimais explícitas do tipo têm atualmente um problema conhecido com setinputsizes(). Para mais informações, veja Executar consultas.

import mssql_python

conn = mssql_python.connect(connection_string)
cursor = conn.cursor()

# Declare types: (sql_type, precision, scale)
cursor.setinputsizes([
    (mssql_python.SQL_WVARCHAR, 100, 0),  # nvarchar(100)
    (mssql_python.SQL_INTEGER, 0, 0),     # int
])

cursor.executemany(
    "SELECT ProductID, Name FROM Production.Product WHERE Name LIKE ? AND ProductSubcategoryID = ?",
    [
        ("Road%", 2),
        ("Mountain%", 1),
    ]
)

Separador decimal

O driver utiliza separadores decimais conscientes da localidade. Para personalizar:

import mssql_python

# Get current separator
sep = mssql_python.getDecimalSeparator()
print(f"Current separator: {sep}")  # Usually "."

# Set custom separator (for locales using comma)
mssql_python.setDecimalSeparator(",")

Conversores de tipo personalizado

Registe conversores personalizados para tipos específicos de SQL:

import mssql_python
from decimal import Decimal

def money_to_float(value):
    """Convert money values to float instead of Decimal."""
    if value is None:
        return None
    return float(value)

conn.add_output_converter(Decimal, money_to_float)

Para mais informações, consulte Conversores de tipo personalizado.

Tipos especiais de alça

Tratamento de UUID

O condutor mapeia uuid.UUID para uniqueidentifier automaticamente. Pode inserir e recuperar UUIDs sem conversão manual de cadeias:

import uuid

cursor.execute("CREATE TABLE #Users (UserId UNIQUEIDENTIFIER PRIMARY KEY, Name NVARCHAR(100))")

# Insert a generated UUID
user_id = uuid.uuid4()
cursor.execute("INSERT INTO #Users (UserId, Name) VALUES (%(user_id)s, %(name)s)", {"user_id": user_id, "name": "Alice"})
conn.commit()

# Retrieve as uuid.UUID object (default behavior)
cursor.execute("SELECT UserId, Name FROM #Users WHERE Name = %(name)s", {"name": "Alice"})
row = cursor.fetchone()
print(f"Type: {type(row.UserId)}")  # <class 'uuid.UUID'>
print(f"UUID: {row.UserId}")        # e.g., 3b4c8f2a-...

# Use the returned UUID directly in subsequent queries
cursor.execute("SELECT Name FROM #Users WHERE UserId = %(user_id)s", {"user_id": row.UserId})

Por defeito, o driver devolve UNIQUEIDENTIFIER as colunas como uuid.UUID objetos. Para devolver cordas maiúsculas compatíveis com pyodbc, defina native_uuid=False:

import uuid

# Per-connection: return UUIDs as strings
conn2 = mssql_python.connect(connection_string, native_uuid=False)
cursor2 = conn2.cursor()
cursor2.execute("CREATE TABLE #UuidDemo (Id UNIQUEIDENTIFIER DEFAULT NEWID(), Label NVARCHAR(50))")
cursor2.execute("INSERT INTO #UuidDemo (Label) VALUES (%(label)s)", {"label": "test"})
conn2.commit()

cursor2.execute("SELECT Id FROM #UuidDemo")
row = cursor2.fetchone()
print(type(row[0]))  # <class 'str'>
print(row[0])        # e.g., 3B4C8F2A-...
conn2.close()

Para configuração ao nível do módulo, consulte a native_uuid definição em Configuração do módulo.

Data-hora com fuso horário

datetimeoffset as colunas devolvem objetos conscientes datetime do fuso horário. Para orientações sobre como trabalhar com valores conscientes do offset versus ingênuos do deslocamento, veja Gestão da data-hora.

cursor.execute("SELECT SYSDATETIMEOFFSET()")
row = cursor.fetchone()
dt = row[0]

print(f"DateTime: {dt}")
print(f"Timezone: {dt.tzinfo}")

Dados geográficos

O driver devolve tipos espaciais (geography, geometry) como bytes. Pode usar cadeias de parâmetros no formato WKT:

# Insert using WKT
cursor.execute("CREATE TABLE #Locations (Name NVARCHAR(100), Geo GEOGRAPHY)")
cursor.execute(
    "INSERT INTO #Locations (Name, Geo) VALUES (%(name)s, geography::STGeomFromText(%(wkt)s, 4326))",
    {"name": "Seattle", "wkt": "POINT(-122.33 47.60)"}
)

# Retrieve as bytes
cursor.execute("SELECT Geo.STAsBinary() FROM #Locations")
row = cursor.fetchone()
geo_bytes = row[0]

Rowversion/timestamp

O SQL Server rowversion (anteriormentetimestamp) é um tipo binário, não uma data-hora:

cursor.execute("""
    CREATE TABLE #RowVersionDemo (
        ID int PRIMARY KEY,
        Version rowversion
    )
""")
cursor.execute("INSERT INTO #RowVersionDemo (ID) VALUES (1)")
cursor.execute("SELECT Version FROM #RowVersionDemo WHERE ID = 1")
row = cursor.fetchone()
version = row[0]  # bytes, not datetime

Tipos de grande valor de fluxo

Ao inserir ou recuperar varchar(max), nvarchar(max), ou varbinary(max) dados, o driver utiliza streaming Data-at-Execution (DAE) para transmitir dados em blocos, em vez de carregar o valor total na memória de uma só vez.

O streaming ativa automaticamente quando os dados de entrada ultrapassam os limiares de tamanho:

Tipo de dados Limiar de transmissão
varchar(max) > 8.000 bytes
nvarchar(max) > 4.000 caracteres
varbinary(max) > 8.000 bytes

O streaming funciona com execute(), executemany(), e todas as APIs de fetch (fetchone(), fetchmany(), fetchall()). O driver não requer configuração especial e gere o streaming automaticamente para valores elevados.

Tipos de SQL Server não suportados

Os seguintes tipos de SQL Server não têm mapeamentos nativos de tipos Python.

Tipo de SQL Server Situação
json Não suportado
vector Não suportado
table Não suportado (parâmetros com valores de tabela)

Sugestão

Embora o json tipo SQL Server não seja suportado diretamente, pode armazenar dados JSON em nvarchar(max) colunas e consultá-los com funções JSON do SQL Server (JSON_VALUE, JSON_QUERY, OPENJSON). Para padrões e exemplos, veja dados JSON.

Os seguintes tipos devolvem dados como bytes mapeamentos nativos de Python mas não possuem:

Tipo de SQL Server Tipo Python Notes
geography bytes Use .STAsBinary() para o formato WKB.
geometry bytes Use .STAsBinary() para o formato WKB.
hierarchyid bytes Representação binária.
sql_variant Variações Resolvido para o tipo base subjacente.

Precisão decimal versus float

Use decimal.Decimal quando a precisão exata for importante, como cálculos financeiros, moeda ou qualquer valor onde erros de arredondamento sejam inaceitáveis. Use float quando valores aproximados são aceitáveis, como medições científicas ou leituras de sensores.

O driver mapeia decimal.Decimal para SQL Server decimal/numeric e preserva a precisão até 38 dígitos. floatmapeia para o SQL Server float (IEEE 754 de 64 bits), que pode introduzir artefactos de arredondamento:

from decimal import Decimal

# Exact - use for currency and financial data
price = Decimal("19.99")
tax_rate = Decimal("0.0825")
total = price * (1 + tax_rate)  # Decimal("21.6391750")

cursor.execute("""
    CREATE TABLE #PrecisionDemo (
        Description NVARCHAR(100),
        DiscountPct DECIMAL(5,2),
        Rating FLOAT
    )
""")

cursor.execute(
    "INSERT INTO #PrecisionDemo (Description, DiscountPct, Rating) VALUES (%(desc)s, %(pct)s, %(rating)s)",
    {"desc": "Summer sale", "pct": Decimal("0.15"), "rating": 4.5}
)

cursor.execute("SELECT DiscountPct, Rating FROM #PrecisionDemo WHERE Description = %(desc)s", {"desc": "Summer sale"})
row = cursor.fetchone()
print(type(row.DiscountPct))  # <class 'decimal.Decimal'>
print(type(row.Rating))       # <class 'float'>

Ao recuperar decimal/numeric colunas, o driver devolve decimal.Decimal sempre objetos. Ao recuperar float/real colunas, o driver devolve Python . float

Warning

Não compares float valores para igualdade. Use antes um intervalo de tolerância: abs(a - b) < 0.0001.

Encadernação tipo entorpecido

O mssql-python driver utiliza isinstance() verificações para determinar os tipos SQL dos parâmetros. Os tipos de inteiros numpy (numpy.int64, numpy.int32, numpy.int8) não passam isinstance(x, int) no NumPy 2.x, o que causa falhas nas ligações. Só numpy.float64 funciona diretamente porque é uma subclasse de Pythonfloat.

Converter valores numpy para tipos nativos de Python antes de os passar como parâmetros:

import numpy as np

row_id = np.int64(42)
score = np.float32(3.14)

# This fails: numpy.int64 is not recognized as int
# cursor.execute("SELECT * FROM Products WHERE ID = ?", (row_id,))

# Convert to native Python types first
cursor.execute(
    "SELECT * FROM Production.Product WHERE ProductID = %(product_id)s",
    {"product_id": int(row_id)}
)

# For DataFrames, convert the whole column
import pandas as pd

df = pd.DataFrame({"ProductID": [1, 2, 3], "Quantity": [10, 20, 30]})

cursor.execute("CREATE TABLE #Orders (ProductID INT, Quantity INT)")

for _, row in df.iterrows():
    cursor.execute(
        "INSERT INTO #Orders (ProductID, Quantity) VALUES (%(product_id)s, %(quantity)s)",
        {"product_id": int(row["ProductID"]), "quantity": int(row["Quantity"])}
    )

Se trabalhas muito com pandas ou dados numpy, considera usar a integração Arrow ou os caminhos de integração pandas , que tratam internamente da conversão de tipos.