Mapeos de tipos de datos para mssql-python

El controlador mssql-python asigna automáticamente los tipos de datos Python a tipos SQL Server al enviar parámetros y convierte los tipos de SQL Server a tipos Python al recuperar los resultados.

Mapeos de Python a SQL Server

Cuando pasas valores de Python como parámetros a execute() o executemany(), el controlador selecciona automáticamente el tipo de SQL Server apropiado. Para la mayoría de las aplicaciones, el mapeo automático es correcto. Úsalo setinputsizes() (descrito más adelante en este artículo) solo cuando necesites sobrescribir el valor por defecto, por ejemplo para forzar varchar en lugar de nvarchar o para controlar metadatos de parámetros para cadenas y entradas enteras.

Tipo de Python Tipo de SQL Server Notas
None NULL SQL NULL value.
bool bit True→1, False→0.
int minúsculo, pequeño,int,bigint Tamaño seleccionado según el rango de valores.
float float Punto flotante de 64 bits.
decimal.Decimal decimal, numérico Preserva la precisión hasta 38 dígitos.
str Varchar, Nvarchar Usa nvarchar para contenido Unicode.
bytes, bytearray varbinary Datos binarios.
datetime.date date Solo fecha.
datetime.time time Solo tiempo.
datetime.datetime datetime2 Fecha y hora con precisión de nanosegundos.
uuid.UUID uniqueidentifier GUID de 16 bytes.

Selección de tipos enteros

El controlador selecciona automáticamente el tipo entero más pequeño que puede contener el valor:

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

Tipos de valor grande

Para cadenas y datos binarios que superan los límites estándar, el controlador utiliza automáticamente los tipos MAX:

Condition Tipo de SQL Server
Cadena > de 8.000 bytes (varchar) varchar(max)
Cadena > de 4.000 caracteres (nvarchar) nvarchar(max)
Binario > de 8.000 bytes varbinary(max)

El controlador transmite valores grandes al servidor para minimizar el uso de memoria.

Mapeos de SQL Server a Python

Cuando el controlador recupera datos de SQL Server, convierte valores a tipos Python:

Tipo de SQL Server Tipo de Python Notas
bit bool Verdadero/Falso.
minúsculo, pequeño,int,bigint int Entero Python (precisión arbitraria).
real float Punto flotante de 32 bits.
float float Punto flotante de 64 bits.
decimal, numérico decimal.Decimal Preserva la precisión.
Dinero, dinero pequeño decimal.Decimal Precisión fija (cuatro decimales).
Char, Varchar, texto str Descifrado como UTF-8.
nchar, nvarchar, ntext str Descodificado como UTF-16LE.
binario, varbinario, imagen bytes Binario puro.
date datetime.date Solo fecha.
time datetime.time Tiempo con precisión de microsegundos.
Hora de cita, Hora de la Cita Pequeña datetime.datetime Tipos de fecha y hora heredados.
datetime2 datetime.datetime Hora de cita de alta precisión.
datetimeoffset datetime.datetime Fecha y hora con conciencia de la zona horaria.
uniqueidentifier uuid.UUID Objetos UUID en Python.
xml str XML como texto.
Geografía, geometría bytes Tipos espaciales como binarios.
hierarchyid bytes Datos de jerarquía como binarios.
sql_variant Varía Resuelto al tipo base subyacente. sql_variant Las columnas utilizan una ruta de obtención en streaming, que puede tener un pequeño impacto en el rendimiento en comparación con las columnas de tipo fijo.
NULL None Python Ninguna.

Constantes de tipo SQL

El controlador exporta constantes que corresponden a identificadores de tipo SQL ODBC. Normalmente usas estas constantes para setinputsizes() anular la inferencia de tipo por defecto del controlador cuando el mapeo automático no coincide con tu esquema.

Tipos de caracteres

Constante Valor Descripción
SQL_CHAR 1 Carácter ANSI de longitud fija.
SQL_VARCHAR 12 Carácter ANSI de longitud variable.
SQL_LONGVARCHAR -1 ANSI largo de longitud variable.
SQL_WCHAR -8 Unicode de longitud fija.
SQL_WVARCHAR -9 Unicode de longitud variable.
SQL_WLONGVARCHAR -10 Unicode largo de longitud variable.

Tipos numéricos

Constante Valor Descripción
SQL_BIT -7 Bit/booleano.
SQL_TINYINT -6 Entero sin signo de 8 bits.
SQL_SMALLINT 5 Entero de 16 bits con signo.
SQL_INTEGER 4 Entero de 32 bits con signo.
SQL_BIGINT -5 Entero con signo de 64 bits.
SQL_REAL 7 Punto flotante de 32 bits.
SQL_FLOAT 6 Punto flotante de 64 bits.
SQL_DOUBLE 8 Punto flotante de 64 bits.
SQL_DECIMAL 3 Decimal de precisión fija.
SQL_NUMERIC 2 Precisión fija numérica.

Tipos de fecha y hora

Constante Valor Descripción
SQL_TYPE_DATE 91 Solo fecha.
SQL_TYPE_TIME 92 Solo tiempo.
SQL_TYPE_TIMESTAMP 93 Fecha y hora.
SQL_SS_TIME2 -154 SQL Server tiempo(n).
SQL_DATETIMEOFFSET -155 SQL Server datetimeoffset.

Note

SQL_SS_TIME2 y SQL_DATETIMEOFFSET son constantes internas que no se exportan como atributos a nivel de módulo. Utiliza los valores enteros (-154, -155) directamente al llamar add_output_converter()a .

Tipos binarios

Constante Valor Descripción
SQL_BINARY -2 Binario de longitud fija.
SQL_VARBINARY -3 Binario de longitud variable.
SQL_LONGVARBINARY -4 Binario largo de longitud variable.

Otros tipos

Constante Valor Descripción
SQL_GUID -11 Identificador único.
SQL_XML -152 Datos XML.
SQL_SS_UDT -151 Tipo definido por el usuario (espacial).
SQL_SS_VARIANT -150 sql_variant datos.

Note

SQL_SS_UDT y SQL_SS_VARIANT son constantes internas que no se exportan como atributos a nivel de módulo. Utiliza los valores enteros (-151, -150) directamente al llamar add_output_converter()a .

Usa setinputsizes()

Llama setinputsizes() antes executemany() para declarar explícitamente los tipos de parámetros cuando la inferencia automática de tipos del controlador causa un comportamiento inesperado, por ejemplo cuando una columna es varchar(100) pero el controlador envía nvarchar:

Note

Para valores decimales, basémonos en la inferencia automática de tipos del controlador en lugar de SQL_DECIMAL o SQL_NUMERIC. Esas constantes explícitas de tipo decimal actualmente tienen un problema conocido con setinputsizes(). Para más información, véase Ejecutar 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

El controlador utiliza separadores decimales con conocimiento local. 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(",")

Convertidores de tipo personalizado

Registra convertidores personalizados para tipos SQL específicos:

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 más información, véase Convertidores de tipo personalizado.

Tipos especiales de manejo

Manejo de UUID

El conductor se asigna uuid.UUID automáticamente uniqueidentifier . Puedes insertar y recuperar UUIDs sin necesidad de conversión manual de cadenas:

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 defecto, el controlador devuelve UNIQUEIDENTIFIER columnas como uuid.UUID objetos. Para devolver cuerdas mayúsculas compatibles con pyodbc, se configura 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 la configuración a nivel de módulo, véase la native_uuid configuración en Configuración de módulos.

Fecha y hora con huso horario

datetimeoffset las columnas devolven objetos conscientes datetime de la zona horaria. Para orientación sobre cómo trabajar con valores conscientes del offset frente a los ingenuos del offset, véase Manejo de la hora de la fecha.

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

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

Datos espaciales

El driver devuelve los tipos espaciales (geography, geometry) como bytes. Puedes usar cadenas de parámetros en 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

El de rowversion SQL Server (anteriormentetimestamp) es un tipo binario, no una fecha y 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 gran valor de flujo

Al insertar o recuperar varchar(max), nvarchar(max), o varbinary(max) datos, el controlador utiliza la transmisión de datos en ejecución (DAE) para transmitir datos en bloques en lugar de cargar el valor completo en la memoria de una vez.

El streaming se activa automáticamente cuando los datos de entrada superan los umbrales de tamaño:

Tipo de dato Umbral de transmisión
varchar(max) > 8.000 bytes
nvarchar(max) > 4.000 caracteres
varbinary(max) > 8.000 bytes

El streaming funciona con execute(), executemany(), y todas las APIs de obtención (fetchone(), fetchmany(), fetchall()). El controlador no requiere ninguna configuración especial y gestiona el streaming automáticamente para valores grandes.

Tipos de SQL Server no soportados

Los siguientes tipos de SQL Server no tienen mapeos nativos de tipos Python.

Tipo de SQL Server Situación
json No soportado
vector No soportado
table No soportado (parámetros con valores de tabla)

Tip

Aunque el json tipo SQL Server no es compatible directamente, puedes almacenar datos JSON en nvarchar(max) columnas y consultarlos con funciones JSON de SQL Server (JSON_VALUE, JSON_QUERY, OPENJSON). Para patrones y ejemplos, véase datos JSON.

Los siguientes tipos devuelven datos como bytes pero no tienen mapeos nativos de tipos Python:

Tipo de SQL Server Tipo de Python Notas
geography bytes Úsalo .STAsBinary() para el formato WKB.
geometry bytes Úsalo .STAsBinary() para el formato WKB.
hierarchyid bytes Representación binaria.
sql_variant Varía Resuelto al tipo base subyacente.

Precisión decimal frente a flotador

Úsalo decimal.Decimal cuando la precisión exacta importe, como cálculos financieros, moneda o cualquier valor donde los errores de redondeo sean inaceptables. Úsalo float cuando los valores aproximados son aceptables, como mediciones científicas o lecturas de sensores.

El controlador se asigna decimal.Decimal a SQL Server decimal/numeric y mantiene la precisión hasta 38 dígitos. floatmapeos a SQL Server float (IEEE 754 de 64 bits), que puede introducir artefactos de redondeo:

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'>

Al recuperar decimal/numeric columnas, el controlador siempre devuelve decimal.Decimal objetos. Al recuperar float/real columnas, el controlador devuelve Python . float

Advertencia

No compares float valores para igualdad. Utiliza un rango de tolerancia en su lugar: abs(a - b) < 0.0001.

Encuadernación tipo entumecido

El mssql-python controlador utiliza isinstance() comprobaciones para determinar los tipos SQL de los parámetros. Los tipos enteros insensibles (numpy.int64, numpy.int32, numpy.int8) no pasan isinstance(x, int) en NumPy 2.x, lo que provoca fallos de enlace. Solo numpy.float64 funciona directamente porque es una subclase de Pythonfloat.

Convierte los valores numpy a tipos nativos de Python antes de pasarlos 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"])}
    )

Si trabajas mucho con pandas o datos numpy, considera usar la integración de Arrow o las rutas de integración de pandas , que gestionan la conversión de tipos internamente.