Mappature dei tipi dati per mssql-python

Il driver mssql-python mappa automaticamente i tipi di dati Python ai tipi SQL Server quando invia i parametri e converte i tipi SQL Server in tipi Python quando recupera i risultati.

Mappaggi da Python a SQL Server

Quando passi valori Python come parametri a execute() o executemany(), il driver seleziona automaticamente il tipo SQL Server appropriato. Per la maggior parte delle applicazioni, la mappatura automatica è corretta. Usa setinputsizes() (descritto più avanti in questo articolo) solo quando devi sovrascrivere il predefinito, ad esempio per forzare varchar invece di nvarchar o per controllare i metadati dei parametri per stringhe e ingressi interi.

Tipo Python Tipo SQL Server Notes
None NULL SQL NULL value.
bool bit True→1, False→0.
int Tinyint, smallint, int,bigint Dimensione selezionata in base all'intervallo di valori.
float float Virgola mobile a 64 bit.
decimal.Decimal decimale, numerica Preserva la precisione fino a 38 cifre.
str Varchar, Nvarchar Usa nvarchar per i contenuti Unicode.
bytes, bytearray varbinary Dati binari.
datetime.date date Solo appuntamento.
datetime.time time Solo il tempo.
datetime.datetime datetime2 Data e ora con precisione di nanosecondi.
uuid.UUID uniqueidentifier GUID da 16 byte.

Selezione dei tipi interi

Il driver seleziona automaticamente il tipo intero più piccolo che può contenere il valore:

Intervallo di valori Tipo SQL Server
da 0 a 255 tinyint
Da -32.768 a 32.767 smallint
Da -2.147.483.648 a 2.147.483.647 int
Valori maggiori bigint

Tipi di grande valore

Per stringhe e dati binari che superano i limiti standard, il driver utilizza automaticamente i tipi MAX:

Condition Tipo SQL Server
Stringa > 8.000 byte (varchar) varchar(max)
Stringa > 4.000 caratteri (nvarchar) nvarchar(max)
Binario > 8.000 byte varbinary(max)

Il driver trasmette valori elevati al server per minimizzare l'uso di memoria.

Mappe da SQL Server a Python

Quando il driver recupera dati da SQL Server, converte i valori in tipi Python:

Tipo SQL Server Tipo Python Notes
bit bool Vero/Falso.
Tinyint, smallint, int,bigint int Intero Python (precisione arbitraria).
real float Virgola mobile a 32 bit.
float float Virgola mobile a 64 bit.
decimale, numerica decimal.Decimal Preserva la precisione.
Soldi, piccoli soldi decimal.Decimal Precisione fissa (quattro decimali).
Char, Varchar, testo str Decodificato come UTF-8.
nchar, nvarchar, ntext str Decodificato come UTF-16LE.
binario, varbinario, immagine bytes Binario grezzo.
date datetime.date Solo appuntamento.
time datetime.time Tempo con precisione di microsecondi.
Ora della data, Piccola Ora datetime.datetime Tipi data-time legacy.
datetime2 datetime.datetime Ora di appuntamento ad alta precisione.
datetimeoffset datetime.datetime Data e ora consapevole del fuso orario.
uniqueidentifier uuid.UUID Oggetti UUID in Python.
xml str XML come testo.
Geografia, Geometria bytes Tipi spaziali come binari.
hierarchyid bytes Dati della gerarchia come binari.
sql_variant Variabile Risolto al tipo base sottostante. sql_variant Le colonne utilizzano un percorso di recupero in streaming, che potrebbe avere un leggero impatto sulle prestazioni rispetto alle colonne di tipo fisso.
NULL None Python nessuno.

Costanti di tipo SQL

Il driver esporta costanti che corrispondono agli identificatori di tipo SQL ODBC. Di solito usi queste costanti per setinputsizes() sovrascrivere l'inferenza di tipo predefinita del driver quando la mappatura automatica non corrisponde al tuo schema.

Tipi di caratteri

Costante Valore Descrizione
SQL_CHAR 1 Carattere ANSI a lunghezza fissa.
SQL_VARCHAR 12 Carattere ANSI a lunghezza variabile.
SQL_LONGVARCHAR -1 ANSI lunga a lunghezza variabile.
SQL_WCHAR -8 Unicode a lunghezza fissa.
SQL_WVARCHAR -9 Unicode a lunghezza variabile.
SQL_WLONGVARCHAR -10 Unicode lungo a lunghezza variabile.

Tipi numerici

Costante Valore Descrizione
SQL_BIT -7 Bit/boolean.
SQL_TINYINT -6 Intero senza segno a 8 bit.
SQL_SMALLINT 5 Intero con segno a 16 bit.
SQL_INTEGER 4 Intero con segno a 32 bit.
SQL_BIGINT -5 Intero con segno a 64 bit.
SQL_REAL 7 Virgola mobile a 32 bit.
SQL_FLOAT 6 Virgola mobile a 64 bit.
SQL_DOUBLE 8 Virgola mobile a 64 bit.
SQL_DECIMAL 3 Decimale di precisione fissa.
SQL_NUMERIC 2 Numerico di precisione fissa.

Tipi di data e ora

Costante Valore Descrizione
SQL_TYPE_DATE 91 Solo appuntamento.
SQL_TYPE_TIME 92 Solo il tempo.
SQL_TYPE_TIMESTAMP 93 Data e ora.
SQL_SS_TIME2 -154 SQL Server time(n).
SQL_DATETIMEOFFSET -155 SQL Server datetimeoffset.

Note

SQL_SS_TIME2 e SQL_DATETIMEOFFSET sono costanti interne non esportate come attributi a livello di modulo. Usa direttamente i valori interi (-154, -155) quando si chiama add_output_converter().

Tipi binari

Costante Valore Descrizione
SQL_BINARY -2 Binario a lunghezza fissa.
SQL_VARBINARY -3 Binario a lunghezza variabile.
SQL_LONGVARBINARY -4 Binario lungo a lunghezza variabile.

Altri tipi

Costante Valore Descrizione
SQL_GUID -11 Identificatore unico.
SQL_XML -152 Dati XML.
SQL_SS_UDT -151 Tipo definito dall'utente (spaziale).
SQL_SS_VARIANT -150 sql_variant dati.

Note

SQL_SS_UDT e SQL_SS_VARIANT sono costanti interne non esportate come attributi a livello di modulo. Usa direttamente i valori interi (-151, -150) quando si chiama add_output_converter().

Usa setinputsizes()

Chiama setinputsizes() prima executemany() per dichiarare esplicitamente i tipi di parametri quando l'inferenza automatica del tipo del driver causa comportamenti inaspettati, ad esempio quando una colonna è varchar(100) ma il driver invia nvarchar:

Note

Per i valori decimali, si basano sull'inferenza automatica di tipo del driver piuttosto che SQL_DECIMAL su o SQL_NUMERIC. Quelle costanti di tipo decimale esplicite attualmente presentano un problema noto con setinputsizes(). Per maggiori informazioni, vedi Esegui query.

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),
    ]
)

Separatore decimale

Il driver utilizza separatori decimali consapevoli della zona. Per personalizzare:

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(",")

Convertitori di tipo personalizzato

Registra convertitori personalizzati per tipi SQL specifici:

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)

Per maggiori informazioni, vedi Convertitori di tipo personalizzati.

Tipi speciali di maniglia

Gestione UUID

Il driver si mappa uuid.UUID su uniqueidentifier automaticamente. Puoi inserire e recuperare UUID senza conversione manuale delle stringhe:

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})

Di default, il driver restituisce UNIQUEIDENTIFIER le colonne come uuid.UUID oggetti. Per restituire stringhe maiuscole compatibili con pyodbc, impostare 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()

Per la configurazione a livello di modulo, vedi l'impostazione native_uuid in Configurazione del modulo.

Data e ora con fuso orario

datetimeoffset le colonne restituiscono oggetti consapevoli datetime del fuso orario. Per indicazioni su come lavorare con valori offset-aware rispetto a offset-naiveive, vedi Gestione Datetime.

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

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

Dati spaziali

Il driver restituisce i tipi spaziali (geography, geometry) come bytes. Puoi usare stringhe di parametri in 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

SQL Server rowversion (precedentemente timestamp) è un tipo binario, non una data-ora:

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

Tipi di grande valore a flusso

Quando inserisce o recupera varchar(max), nvarchar(max), o varbinary(max) dati, il driver utilizza lo streaming Data-at-Execution (DAE) per trasmettere i dati a blocchi invece di caricare l'intero valore in memoria contemporaneamente.

Lo streaming si attiva automaticamente quando i dati di input superano le soglie di dimensione:

Tipo di dati Soglia di streaming
varchar(max) > 8.000 byte
nvarchar(max) > 4.000 caratteri
varbinary(max) > 8.000 byte

Lo streaming funziona con execute(), executemany(), e tutte le API di fetch (fetchone(), fetchmany(), fetchall()). Il driver non richiede una configurazione speciale e gestisce automaticamente lo streaming per valori elevati.

Tipi di SQL Server non supportati

I seguenti tipi di SQL Server non hanno mappe nativi di tipo Python.

Tipo SQL Server Condizione
json Non supportato
vector Non supportato
table Non supportato (parametri a valori di tabella)

Tip

Anche se il json tipo SQL Server non è supportato direttamente, puoi memorizzare dati JSON in nvarchar(max) colonne e interrogarli con le funzioni JSON di SQL Server (JSON_VALUE, JSON_QUERY, OPENJSON). Per pattern ed esempi, vedi dati JSON.

I seguenti tipi restituiscono dati come bytes ma non hanno mappe nativi di tipo Python:

Tipo SQL Server Tipo Python Notes
geography bytes Usa .STAsBinary() per il formato WKB.
geometry bytes Usa .STAsBinary() per il formato WKB.
hierarchyid bytes Rappresentazione binaria.
sql_variant Variabile Risolto al tipo base sottostante.

Precisione decimale contro float

Usalo decimal.Decimal quando la precisione esatta è importante, come calcoli finanziari, valuta o qualsiasi valore in cui gli errori di arrotondamento sono inaccettabili. Utilizzare float quando valori approssimati sono accettabili, come misurazioni scientifiche o letture dei sensori.

Il driver si mappa decimal.Decimal su SQL Server decimal/numeric e mantiene la precisione fino a 38 cifre. floatmappa a SQL Server float (IEEE 754 a 64 bit), che può introdurre artefatti di arrotondamento:

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

Quando si recuperano decimal/numeric colonne, il driver restituisce decimal.Decimal sempre oggetti. Quando si recuperano float/real le colonne, il driver restituisce Python float.

Warning

Non confrontare float i valori per l'uguaglianza. Usa invece un intervallo di tolleranza: abs(a - b) < 0.0001.

Rilegato tipo insensibile

Il mssql-python driver utilizza isinstance() controlli per determinare i tipi SQL per i parametri. I tipi di interi Numpy (numpy.int64, numpy.int32, numpy.int8) non passano isinstance(x, int) in NumPy 2.x, il che causa fallimenti di binding. Funziona direttamente solo numpy.float64 perché è una sottoclasse di Pythonfloat.

Converti i valori numpy in tipi nativi di Python prima di passarli come parametri:

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 lavori molto con pandas o dati numpy, considera di usare l'integrazione Arrow o i percorsi di integrazione pandas , che gestiscono internamente la conversione dei tipi.