Mappings typu danych dla mssql-python

Sterownik mssql-python automatycznie mapuje typy danych Python na typy SQL Server podczas wysyłania parametrów i konwertuje typy SQL Server na typy Python podczas pobierania wyników.

Mappingi Python do SQL Server

Gdy przekazujesz wartości Python jako parametry do execute() lub executemany(), sterownik automatycznie wybiera odpowiedni typ SQL Server. W większości zastosowań automatyczne mapowanie jest poprawne. Używaj setinputsizes() (opisanego później w tym artykule) tylko wtedy, gdy musisz nadpisać domyślne, na przykład aby wymusić varchar zamiast nvarchar lub kontrolować metadane parametrów dla łańcuchów i liczb całkowitych.

Typ języka Python Typ programu SQL Server Notatki
None NULL Wartość SQL NULL.
bool bit True→1, False→0.
int tinyint, smallint, int, bigint Rozmiar wybierany w zależności od zakresu wartości.
float float 64-bitowy zmiennoprzecinkowy.
decimal.Decimal Dziesiętny, numeryczny Zachowuje precyzję do 38 cyfr.
str Varchar, Nvarchar Używa nvarchar do zawartości Unicode.
bytes, bytearray varbinary Dane binarne.
datetime.date date Tylko randka.
datetime.time time Tylko czas.
datetime.datetime datetime2 Data i czas z precyzją nanosekund.
uuid.UUID uniqueidentifier 16-bajtowy GUID.

Wybór typu całkowitego

Sterownik automatycznie wybiera najmniejszy typ liczby całkowitej, który może pomieścić tę wartość:

Zakres wartości Typ programu SQL Server
Od 0 do 255 tinyint
-32,768 do 32,767 smallint
-2,147,483,648 do 2,147,483,647 int
Większe wartości bigint

Typy o dużej wartości

Dla łańcuchów i danych binarnych przekraczających standardowe limity, sterownik automatycznie używa typów MAX:

Warunek Typ programu SQL Server
Ciąg > 8 000 bajtów (varchar) varchar(max)
String > 4 000 chars (nvarchar) nvarchar(max)
Binarne > 8 000 bajtów varbinary(max)

Sterownik przesyła duże wartości do serwera, aby zminimalizować zużycie pamięci.

Mappingi SQL Server do Python

Gdy sterownik pobiera dane z SQL Server, konwertuje wartości na typy w Python:

Typ programu SQL Server Typ języka Python Notatki
bit bool Prawda/fałsz.
tinyint, smallint, int, bigint int Python integer (dowolna precyzja).
prawdziwy float 32-bitowy zmiennoprzecinkowa.
float float 64-bitowy zmiennoprzecinkowy.
Dziesiętny, numeryczny decimal.Decimal Zachowuje precyzję.
pieniądze, drobne pieniądze decimal.Decimal Stała precyzja (cztery miejsca po przecinku).
Char, Varchar, tekst str Rozszyfrowane jako UTF-8.
nchar, nvarchar, ntext str Rozszyfrowane jako UTF-16LE.
binarny, varbinary, obraz bytes Surowa binarność.
date datetime.date Tylko randka.
time datetime.time Czas z mikrosekundową precyzją.
randka,mała randkagodzina datetime.datetime Starsze typy randki.
datetime2 datetime.datetime Bardzo precyzyjny czas randkowy.
datetimeoffset datetime.datetime Czas randkowy świadomy strefy czasowej.
uniqueidentifier uuid.UUID Obiekty UUID Python.
xml str XML jako tekst.
Geografia, geometria bytes Typy przestrzenne jako binarne.
hierarchyid bytes Dane hierarchiczne jako binarne.
sql_variant Varies Rozwiązane do podstawowego typu bazowego. sql_variant Kolumny korzystają ze ścieżki pobierania strumieniowej, co może mieć niewielki wpływ na wydajność w porównaniu do kolumn typu stałego.
NULL None Python Żadna.

Stałe typu SQL

Sterownik eksportuje stałe odpowiadające identyfikatorom typu SQL ODBC. Zazwyczaj używasz tych stałych z , setinputsizes() aby nadpisać domyślne wnioskowanie typu sterownika, gdy automatyczne mapowanie nie odpowiada twojemu schematowi.

Typy znaków

Stały Wartość Opis
SQL_CHAR 1 Znak ANSI o stałej długości.
SQL_VARCHAR 12 Znak ANSI o zmiennej długości.
SQL_LONGVARCHAR -1 Długie ANSI o zmiennej długości.
SQL_WCHAR -8 Unicode o stałej długości.
SQL_WVARCHAR -9 Unicode o zmiennej długości.
SQL_WLONGVARCHAR -10 Długi Unicode o zmiennej długości.

Typy liczbowe

Stały Wartość Opis
SQL_BIT -7 Bit/boolean.
SQL_TINYINT -6 8-bitowa liczba całkowita bez znaku.
SQL_SMALLINT 5 16-bitowa liczba całkowita ze znakiem.
SQL_INTEGER 4 32-bitowa liczba całkowita ze znakiem.
SQL_BIGINT -5 64-bitowa liczba całkowita ze znakiem.
SQL_REAL 7 32-bitowy zmiennoprzecinkowa.
SQL_FLOAT 6 64-bitowy zmiennoprzecinkowy.
SQL_DOUBLE 8 64-bitowy zmiennoprzecinkowy.
SQL_DECIMAL 3 Stała precyzja dziesiętna.
SQL_NUMERIC 2 Stała precyzja numeryczna.

Typy dat i godzin

Stały Wartość Opis
SQL_TYPE_DATE 91 Tylko randka.
SQL_TYPE_TIME 92 Tylko czas.
SQL_TYPE_TIMESTAMP 93 Data i godzina.
SQL_SS_TIME2 -154 SQL Server time(n).
SQL_DATETIMEOFFSET -155 SQL Server datetimeoffset.

Note

SQL_SS_TIME2 oraz SQL_DATETIMEOFFSET są stałymi wewnętrznymi, które nie są eksportowane jako atrybuty na poziomie modułu. Używaj wartości całkowitych (-154, -155) bezpośrednio podczas wywoływania add_output_converter().

Typy binarne

Stały Wartość Opis
SQL_BINARY -2 Binarny o stałej długości.
SQL_VARBINARY -3 Binarny o zmiennej długości.
SQL_LONGVARBINARY -4 Długi binarny o zmiennej długości.

Inne typy

Stały Wartość Opis
SQL_GUID -11 Unikalny identyfikator.
SQL_XML -152 Dane XML.
SQL_SS_UDT -151 Typ zdefiniowany przez użytkownika (przestrzenny).
SQL_SS_VARIANT -150 sql_variant danych.

Note

SQL_SS_UDT oraz SQL_SS_VARIANT są stałymi wewnętrznymi, które nie są eksportowane jako atrybuty na poziomie modułu. Używaj wartości całkowitych (-151, -150) bezpośrednio podczas wywoływania add_output_converter().

Użyj setinputsizes()

Wywołaj przed setinputsizes() wywołaniemexecutemany(), aby jawnie zadeklarować typy parametrów, gdy automatyczne wnioskowanie typu sterownika powoduje nieoczekiwane zachowanie, na przykład gdy kolumna jest, varchar(100) ale sterownik wysyła nvarchar:

Note

Dla wartości dziesiętnych polegaj na automatycznym wnioskowaniu typów kierowcy, a nie SQL_DECIMAL na lub SQL_NUMERIC. Te jawne stałe typu dziesiętnego mają obecnie znany problem z .setinputsizes() Więcej informacji można znaleźć w artykule Wykonaj zapytania.

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

Separator dziesiętny

Sterownik używa separatorów dziesiętnych uwzględniających lokalizację. Opcje dostosowania:

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

Konwertery niestandardowe typu

Rejestruj niestandardowe konwertery dla konkretnych typów 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)

Więcej informacji można znaleźć w artykule Niestandardowe przetworniki typu.

Specjalne typy uchwytów

Obsługa UUID

Sterownik automatycznie się mapuje uuid.UUIDuniqueidentifier . Możesz wstawiać i pobierać UUID bez ręcznej konwersji ciągów znaków:

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

Domyślnie sterownik zwraca UNIQUEIDENTIFIER kolumny jako uuid.UUID obiekty. Aby zwrócić ciągi znaków zgodnych z pyodbc, ustaw 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()

Aby poznać konfigurację na poziomie modułu, zobacz native_uuid ustawienia w konfiguracji modułu.

Czas daty ze strefą czasową

datetimeoffset kolumny zwracają obiekty uwzględniające datetime strefy czasowe. Aby uzyskać wskazówki dotyczące pracy z wartościami świadomymi offsetu a wartościami naiwnymi offsetowymi, zobacz Obsługa czasu datowego.

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

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

Dane przestrzenne

Sterownik zwraca typy przestrzenne (geography, geometry) jako .bytes Możesz używać ciągów parametrów w formacie 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]

wersja wiersza/znacznik czasu

SQL Server (dawniej rowversion) jest timestamp typem binarnym, a nie datą:

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

Strumienie dużych wartości

Podczas wstawiania lub pobierania varchar(max), nvarchar(max), lub varbinary(max) danych, sterownik korzysta ze strumieniowania danych przy wykonaniu (DAE) do przesyłania danych w fragmentach, zamiast ładować całą wartość do pamięci jednocześnie.

Streaming aktywuje się automatycznie, gdy dane wejściowe przekraczają progi rozmiaru:

Typ danych Próg strumieniowania
varchar(max) > 8 000 bajtów
nvarchar(max) > 4 000 znaków
varbinary(max) > 8 000 bajtów

Streaming działa z execute(), executemany(), oraz wszystkimi API pobierania (fetchone(), fetchmany(), ). fetchall() Sterownik nie wymaga specjalnej konfiguracji i obsługuje automatyczne strumieniowanie dla dużych wartości.

Nieobsługiwane typy SQL Server

Poniższe typy SQL Server nie mają natywnych mapowań typów Python.

Typ programu SQL Server Status
json Niewspierane
vector Niewspierane
table Nie obsługiwane (parametry tabelowe)

Wskazówka

Chociaż typ SQL Server nie jest bezpośrednio obsługiwany json , można przechowywać dane JSON w nvarchar(max) kolumnach i zapytywać je za pomocą funkcji JSON w SQL Server (JSON_VALUE, JSON_QUERY, ). OPENJSON Wzorce i przykłady można znaleźć w danych JSON.

Następujące typy zwracają dane jako bytes natywne mapowania typów Python, ale nie posiadają:

Typ programu SQL Server Typ języka Python Notatki
geography bytes Zastosowanie .STAsBinary() w formacie WKB.
geometry bytes Zastosowanie .STAsBinary() w formacie WKB.
hierarchyid bytes Reprezentacja binarna.
sql_variant Varies Rozwiązane do podstawowego typu bazowego.

Precyzja dziesiętna vs pływająca

Używaj wtedy decimal.Decimal , gdy istotna jest dokładna precyzja, na przykład przy obliczeniach finansowych, pieniądzu lub w jakiejkolwiek wartości, gdzie błędy zaokrągleń są nie do przyjęcia. Stosuj, float gdy wartości przybliżone są akceptowalne, na przykład w pomiarach naukowych lub odczytach z czujników.

Sterownik mapuje decimal.Decimal się na SQL Server decimal/numeric i zachowuje precyzję do 38 cyfr. floatmapuje do SQL Server float (64-bitowy IEEE 754), który może wprowadzać artefakty zaokrągleń:

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

Podczas pobierania decimal/numeric kolumn sterownik zawsze zwraca decimal.Decimal obiekty. Podczas pobierania float/real kolumn sterownik zwraca Python . float

Warning

Nie porównuj float wartości równości. Zamiast tego użyj zakresu tolerancji: abs(a - b) < 0.0001.

Oprawę typu numpy

Sterownik mssql-python wykorzystuje isinstance() kontrole do określania typów SQL dla parametrów. Typy liczb całkowitych Numpy (numpy.int64, numpy.int32, ) numpy.int8nie przechodzą isinstance(x, int) w NumPy 2.x, co powoduje awarie wiązania. Działa to tylko numpy.float64 bezpośrednio, bo to podklasa Pythonfloat.

Przekonwertuj wartości numpy na natywne typy Python przed przekazaniem ich jako parametrów:

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

Jeśli intensywnie pracujesz z pandas lub numpy data, rozważ użycie ścieżek integracji z Arrow lub pandas , które obsługują konwersję typów wewnętrznie.