Datentypabbildungen für mssql-python

Der mssql-python-Treiber bildet beim Senden von Parametern automatisch Python-Datentypen auf SQL Server-Typen ab und wandelt SQL Server-Typen in Python-Typen um, wenn Ergebnisse abgerufen werden.

Python-zu-SQL Server-Zuordnungen

Wenn du Python-Werte als Parameter an execute() oder executemany()gibst, wählt der Treiber automatisch den entsprechenden SQL Server-Typ. Für die meisten Anwendungen ist die automatische Zuordnung korrekt. Verwenden setinputsizes() Sie (später in diesem Artikel beschrieben) nur, wenn Sie den Standard überschreiben müssen, zum Beispiel um varchar statt nvarchar zu erzwingen oder um Parametermetadaten für String- und Ganzzahleingaben zu steuern.

Python-Typ SQL Server-Typ Hinweise
None NULL SQL NULL-Wert.
bool bit True→1, False→0.
int winzig, klein,int, bigint Größe wird basierend auf dem Wertbereich ausgewählt.
float float 64-Bit-Gleitkomma.
decimal.Decimal Dezimal, numerisch Bewahrt eine Präzision bis zu 38 Ziffern.
str Varchar, Nvarchar Verwendet nvarchar für Unicode-Inhalte.
bytes, bytearray varbinary Binäre Daten.
datetime.date date Nur Datum.
datetime.time Zeit Nur Zeit.
datetime.datetime datetime2 Datum und Uhrzeit mit Nanosekundenpräzision.
uuid.UUID uniqueidentifier 16-Byte GUID.

Ganzzahlige Typauswahl

Der Treiber wählt automatisch den kleinsten ganzzahligen Typ, der den Wert halten kann:

Wertbereich SQL Server-Typ
0 bis 255 tinyint
–32.768 bis 32.767 smallint
-2,147,483,648 bis 2,147,483,647 int
Höhere Werte bigint

Große Wert-Typen

Für Strings und Binärdaten, die Standardlimits überschreiten, verwendet der Treiber automatisch MAX-Typen:

Zustand SQL Server-Typ
String > 8.000 Bytes (varchar) varchar(max)
String > 4.000 Zeichen (nvarchar) nvarchar(max)
Binär: 8.000 Bytes > varbinary(max)

Der Treiber streamt große Werte an den Server, um den Speicherverbrauch zu minimieren.

SQL Server-zu-Python-Mappings

Wenn der Treiber Daten aus dem SQL Server abruft, wandelt er Werte in Python-Typen um:

SQL Server-Typ Python-Typ Hinweise
bit bool Wahr/Falsch.
winzig, klein,int, bigint int Python Ganzzahl (beliebige Genauigkeit).
real float 32-Bit-Gleitkomma.
float float 64-Bit-Gleitkomma.
Dezimal, numerisch decimal.Decimal Bewahrt die Präzision.
Geld, Kleingeld decimal.Decimal Feste Genauigkeit (vier Dezimalstellen).
Char, Varchar, Text str Entschlüsselt als UTF-8.
nchar, nvarchar, ntext str Entschlüsselt als UTF-16LE.
Binär,Varbinär, Bild bytes Rohe Binär.
date datetime.date Nur Datum.
Zeit datetime.time Zeit mit Mikrosekundenpräzision.
Datetime, SmallDatetime datetime.datetime Legacy-Datetime-Typen.
datetime2 datetime.datetime Hochpräzise Datumszeit.
datetimeoffset datetime.datetime Zeitzonenbewusste Datezeit.
uniqueidentifier uuid.UUID Python UUID-Objekte.
xml str XML als Text.
Geografie, Geometrie bytes Räumliche Typen als binär.
hierarchyid bytes Hierarchiedaten als Binär.
sql_variant Variiert Auf den zugrundeliegenden Basistyp aufgelöst. sql_variant Spalten verwenden einen Streaming-Fetch-Pfad, der im Vergleich zu Spalten mit festem Typ einen leichten Leistungseinfluss haben kann.
NULL None Python Keine.

SQL-Typkonstanten

Der Treiber exportiert Konstanten, die den ODBC SQL-Typ-Identifikatoren entsprechen. Du verwendest diese Konstanten typischerweise mit setinputsizes() , um die Standardtyp-Inferenz des Fahrers zu überschreiben, wenn die automatische Zuordnung nicht mit deinem Schema übereinstimmt.

Zeichentypen

Dauerhaft Wert Beschreibung
SQL_CHAR 1 ANSI-Zeichen mit fester Länge.
SQL_VARCHAR 12 ANSI-Zeichen variabler Länge.
SQL_LONGVARCHAR -1 Lange, variable ANSI (ANSI).
SQL_WCHAR -8 Unicode mit fester Länge.
SQL_WVARCHAR -9 Unicode mit variabler Länge.
SQL_WLONGVARCHAR -10 Langer, variabler Länge Unicode.

Numerische Typen

Dauerhaft Wert Beschreibung
SQL_BIT -7 Bit/boolean.
SQL_TINYINT -6 8-Bit-Ganzzahl ohne Vorzeichen.
SQL_SMALLINT 5 16-Bit-Ganzzahl mit Vorzeichen.
SQL_INTEGER 4 32-Bit-Ganzzahl mit Vorzeichen.
SQL_BIGINT -5 64-Bit-signierte Ganzzahl.
SQL_REAL 7 32-Bit-Gleitkomma.
SQL_FLOAT 6 64-Bit-Gleitkomma.
SQL_DOUBLE 8 64-Bit-Gleitkomma.
SQL_DECIMAL 3 Feste Dezimalgenauigkeit.
SQL_NUMERIC 2 Zahlengenauigkeit mit fester Genauigkeit.

Datums- und Uhrzeittypen

Dauerhaft Wert Beschreibung
SQL_TYPE_DATE 91 Nur Datum.
SQL_TYPE_TIME 92 Nur Zeit.
SQL_TYPE_TIMESTAMP 93 Datum und Uhrzeit.
SQL_SS_TIME2 -154 SQL Server time(n).
SQL_DATETIMEOFFSET –155 SQL Server datetimeoffset.

Note

SQL_SS_TIME2 und SQL_DATETIMEOFFSET sind interne Konstanten, die nicht als modulbezogene Attribute exportiert werden. Verwenden Sie direkt die ganzzahligen Werte (-154, -155), wenn Sie aufgerufen add_output_converter()werden.

Binäre Typen

Dauerhaft Wert Beschreibung
SQL_BINARY -2 Binäre Länge mit fester Länge.
SQL_VARBINARY -3 Binärfunktion mit variabler Länge.
SQL_LONGVARBINARY –4 Lange, variable Binärlänge.

Andere Typen

Dauerhaft Wert Beschreibung
SQL_GUID -11 Einzigartiger Identifikator.
SQL_XML –152 XML-Daten.
SQL_SS_UDT –151 Benutzerdefinierter Typ (räumlich).
SQL_SS_VARIANT -150 sql_variant Daten.

Note

SQL_SS_UDT und SQL_SS_VARIANT sind interne Konstanten, die nicht als modulbezogene Attribute exportiert werden. Verwenden Sie direkt die ganzzahligen Werte (-151, -150), wenn Sie aufgerufen add_output_converter()werden.

Verwenden Sie setinputsizes()

Ruf vorher auf setinputsizes() , executemany() um explizit Parametertypen zu deklarieren, wenn die automatische Typinferenz des Fahrers unerwartetes Verhalten verursacht, zum Beispiel wenn eine Spalte ist varchar(100) , aber der Treiber sendet nvarchar:

Note

Für Dezimalwerte verlassen Sie sich auf die automatische Typinferenz des Fahrers statt SQL_DECIMAL auf oder SQL_NUMERIC. Diese expliziten Dezimaltypkonstanten haben derzeit ein bekanntes Problem mit setinputsizes(). Weitere Informationen finden Sie unter Abfragen ausführen.

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

Dezimaltrennzeichen

Der Fahrer verwendet lokalisierte Dezimaltrenner. Zum Anpassen:

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

Individuelle Wandler

Registrieren Sie benutzerdefinierte Konverter für bestimmte SQL-Typen:

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)

Weitere Informationen finden Sie unter Custom type Converters.

Handle spezielle Typen

UUID-Handhabung

Der Treiber wird automatisch zugeordnet uuid.UUIDuniqueidentifier . Du kannst UUIDs ohne manuelle String-Umwandlung einfügen und abrufen:

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

Standardmäßig gibt der Treiber Spalten als UNIQUEIDENTIFIER Objekte zurückuuid.UUID. Um stattdessen pyodbc-kompatible Großbuchstaben-Zeichenketten zurückzugeben, setze 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()

Für die Konfiguration auf Modulebene siehe die native_uuidEinstellung in Modulkonfiguration.

Datumszeit mit Zeitzone

datetimeoffset Spalten geben zeitzonenbewusste datetime Objekte zurück. Für Hinweise zum Umgang mit offset-bewussten versus offset-naiven Werten siehe Datetime-Handling.

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

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

Räumliche Daten

Der Treiber gibt räumliche Typen (geography, geometry) als zurück bytes. Sie können Parameterstrings im WKT-Format verwenden:

# 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]

Reihenversion/Zeitstempel

SQL Server rowversion (früher timestamp) ist ein binärer Typ, kein Datetime:

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

Stream-Großwerttypen

Beim Einfügen oder Abrufen varchar(max)von , nvarchar(max), oder varbinary(max) Daten, verwendet der Treiber Data-at-Execution (DAE)-Streaming, um Daten in Chunks zu übertragen, anstatt den gesamten Wert auf einmal in den Speicher zu laden.

Das Streaming wird automatisch aktiviert, wenn die Eingabedaten die Größenschwellenwerte überschreiten:

Datentyp Streaming-Schwelle
varchar(max) > 8.000 Bytes
nvarchar(max) > 4.000 Zeichen
varbinary(max) > 8.000 Bytes

Streaming funktioniert mit execute(), executemany(), und allen Fetch-APIs (fetchone(), fetchmany(), fetchall()). Der Treiber benötigt keine spezielle Konfiguration und übernimmt das Streaming automatisch für große Werte.

Nicht unterstützte SQL Server-Typen

Die folgenden SQL Server-Typen haben keine nativen Python-Typzuordnungen.

SQL Server-Typ Status
json Nicht unterstützt
vector Nicht unterstützt
Tabelle Nicht unterstützt (tabellenwertige Parameter)

Tip

Obwohl der json SQL Server-Typ nicht direkt unterstützt wird, kann man JSON-Daten in nvarchar(max) Spalten speichern und sie mit SQL Server-JSON-Funktionen abfragen (JSON_VALUE, JSON_QUERY, OPENJSON). Für Muster und Beispiele siehe JSON-Daten.

Die folgenden Typen geben Daten zurückbytes, haben aber keine nativen Python-Typ-Mappings:

SQL Server-Typ Python-Typ Hinweise
geography bytes Verwendung .STAsBinary() für das WKB-Format.
geometry bytes Verwendung .STAsBinary() für das WKB-Format.
hierarchyid bytes Binäre Repräsentation.
sql_variant Variiert Auf den zugrundeliegenden Basistyp aufgelöst.

Dezimal- versus Schwimmergenauigkeit

Verwenden decimal.Decimal Sie, wenn genaue Genauigkeit wichtig ist, wie bei finanziellen Berechnungen, Währung oder jedem Wert, bei dem Rundungsfehler nicht akzeptabel sind. Verwenden float Sie, wenn ungefähre Werte akzeptabel sind, wie wissenschaftliche Messungen oder Sensormessungen.

Der Treiber wird auf SQL Server decimal.Decimaldecimal/ abgebildet numeric und erhält eine Genauigkeit von bis zu 38 Ziffern. floatwird auf den SQL Server float (64-Bit-IEEE 754) abgebildet, der Rundungsartefakte einführen kann:

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

Beim Abrufen decimal/numericvon Spalten gibt der Treiber immer Objekte zurück.decimal.Decimal Beim Abrufen float/realvon Spalten gibt der Treiber Python floatzurück.

Warning

Vergleiche float keine Werte für Gleichheit. Verwenden Sie stattdessen einen Toleranzbereich: abs(a - b) < 0.0001.

Numpy-Typbindung

Der Treiber mssql-python verwendet isinstance() Prüfungen, um SQL-Typen für Parameter zu bestimmen. Numpy-Ganzzahltypen (numpy.int64, numpy.int32, numpy.int8) passieren isinstance(x, int) in NumPy 2.x nicht, was zu Bindungsfehlern führt. Funktioniert nur numpy.float64 direkt, weil es eine Unterklasse von Python floatist.

Konvertiere Numpy-Werte in native Python-Typen, bevor du sie als Parameter übergibst:

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

Wenn du stark mit Pandas oder Numpy-Daten arbeitest, solltest du die Arrow-Integration oder pandas-Integrationspfade nutzen, die intern die Typkonvertierung übernehmen.