mssql-pythonドライバーはパラメータを送信時にPythonデータ型を自動的にSQL Server型にマッピングし、結果を取得する際にSQL Server型をPython型に変換します。
PythonからSQL Serverへのマッピング
Python値をパラメータとしてexecute()やexecutemany()に渡すと、ドライバーは自動的に適切なSQL Serverタイプを選択します。 ほとんどの用途では、自動マッピングは正確です。
setinputsizes()(この記事の後述で説明します)は、デフォルトを上書きする必要がある場合、例えばnvarcharの代わりにvarcharを強制したり、文字列や整数入力のパラメータメタデータを制御する場合のみ使用してください。
| Python 型 | SQL Server の種類 | Notes |
|---|---|---|
None |
NULL |
SQLのNULL値。 |
bool |
bit |
True→1、 False→0。 |
int |
ティニート、 スモールリント、 イント、 ビジント | サイズは値段に基づいて選択します。 |
float |
float | 64ビット浮動小数点。 |
decimal.Decimal |
十進法、 数値 | 最大38桁までの精度を保持します。 |
str |
ヴァルチャール、 ンヴァルチャール | Unicodeのコンテンツには nvarchar を使用しています。 |
bytes、bytearray |
varbinary | バイナリ データ。 |
datetime.date |
date | 日付のみ。 |
datetime.time |
time | 時間だけだ。 |
datetime.datetime |
datetime2 | ナノ秒単位の精度で日付と時間。 |
uuid.UUID |
uniqueidentifier | 16バイトのガイド。 |
整数型選択
ドライバーは自動的に、次の値を保持できる最小の整数型を選択します。
| 値の範囲 | SQL Server の種類 |
|---|---|
| 0 ~ 255 | tinyint |
| -32,768 ~ 32,767 | smallint |
| -2,147,483,648 ~ 2,147,483,647 | int |
| より大きな値 | bigint |
大きな価値タイプ
標準制限を超える文字列やバイナリデータの場合、ドライバーは自動的にMAX型を使用します:
| 状態 | SQL Server の種類 |
|---|---|
| 文字列 > 8,000バイト(varchar) | varchar(max) |
| 文字列 > 4,000 chars(nvarchar) | nvarchar(max) |
| バイナリ > 8,000バイト | varbinary(max) |
ドライバーはメモリ使用を最小限に抑えるために大きな値をサーバーにストリーミングします。
SQL ServerからPythonへのマッピング
ドライバーがSQL Serverからデータを取得する際、値をPython型に変換します:
| SQL Server の種類 | Python 型 | Notes |
|---|---|---|
| bit | bool |
正/誤 |
| ティニート、 スモールリント、 イント、 ビジント | int |
Python整数(任意の精度)。 |
| 実数 | float |
32 ビット浮動小数点。 |
| float | float |
64ビット浮動小数点。 |
| 十進法、 数値 | decimal.Decimal |
精度を保つ。 |
| お金、 小さなお金 | decimal.Decimal |
固定精度(小数点以下4桁)です。 |
| char、 varchar、 テキスト | str |
UTF-8としてデコードされました。 |
| nchar、 nvarchar、 ntext | str |
UTF-16LEとしてデコードされました。 |
| binary、varbinary、image | bytes |
生のバイナリです。 |
| date | datetime.date |
日付のみ。 |
| time | datetime.time |
マイクロ秒単位の精度で時間。 |
| デートタイム、 スモールデイトタイム | datetime.datetime |
昔ながらのデートタイムタイプ。 |
| datetime2 | datetime.datetime |
高精度のデートタイム。 |
| datetimeoffset | datetime.datetime |
タイムゾーンを意識した日付時間。 |
| uniqueidentifier | uuid.UUID |
Python UUIDオブジェクト。 |
| xml | str |
XMLをテキストとして使う。 |
| 地理、 幾何学 | bytes |
空間タイプは二項法として扱います。 |
| hierarchyid | bytes |
階層データをバイナリとして扱う。 |
| sql_variant | 場合により異なる | 基礎となるベースタイプに解決します。
sql_variant カラムはストリーミングフェッチパスを使用しており、固定型カラムと比べてわずかなパフォーマンスに影響がある場合があります。 |
NULL |
None |
Python なし。 |
SQL型定数
ドライバーはODBC SQL型識別子に対応する定数をエクスポートします。 通常、これらの定数を setinputsizes() 使って、自動マッピングがスキーマと一致しない場合にドライバーのデフォルトのタイプ推論を上書きします。
文字型
| 定数 | 価値 | 形容 |
|---|---|---|
SQL_CHAR |
1 | 固定長ANSI文字。 |
SQL_VARCHAR |
12 | 可変長ANSI文字。 |
SQL_LONGVARCHAR |
-1 | 長距離可変長ANSI。 |
SQL_WCHAR |
-8 | 固定長のUnicode。 |
SQL_WVARCHAR |
-9 | 可変長Unicode。 |
SQL_WLONGVARCHAR |
-10 | 長く可変長のUnicode。 |
数値型
| 定数 | 価値 | 形容 |
|---|---|---|
SQL_BIT |
-7 | ビット/ブール数です。 |
SQL_TINYINT |
-6 | 8 ビット符号なし整数。 |
SQL_SMALLINT |
5 | 16 ビット符号付き整数。 |
SQL_INTEGER |
4 | 32 ビット符号付き整数。 |
SQL_BIGINT |
-5 | 64ビット符号付き整数。 |
SQL_REAL |
7 | 32 ビット浮動小数点。 |
SQL_FLOAT |
6 | 64ビット浮動小数点。 |
SQL_DOUBLE |
8 | 64ビット浮動小数点。 |
SQL_DECIMAL |
3 | 固定精度の十進法。 |
SQL_NUMERIC |
2 | 固定精度の数値。 |
日付/時刻型
| 定数 | 価値 | 形容 |
|---|---|---|
SQL_TYPE_DATE |
91 | 日付のみ。 |
SQL_TYPE_TIME |
92 | 時間だけだ。 |
SQL_TYPE_TIMESTAMP |
93 | 日付と時刻。 |
SQL_SS_TIME2 |
-154 | SQL Server time(n). |
SQL_DATETIMEOFFSET |
-155 | SQL Server datetimeoffset. |
Note
SQL_SS_TIME2
SQL_DATETIMEOFFSETはモジュールレベルの属性としてエクスポートされない内部定数です。
-154を呼ぶ際には整数の値(-155、add_output_converter())を直接使います。
バイナリ型
| 定数 | 価値 | 形容 |
|---|---|---|
SQL_BINARY |
-2 | 固定長のバイナリ。 |
SQL_VARBINARY |
-3 | 可変長のバイナリ。 |
SQL_LONGVARBINARY |
-4 | 長可変長のバイナリ。 |
その他の型
| 定数 | 価値 | 形容 |
|---|---|---|
SQL_GUID |
-11 | ユニーク識別子。 |
SQL_XML |
-152 | XML データ。 |
SQL_SS_UDT |
-151 | ユーザー定義型(空間型)。 |
SQL_SS_VARIANT |
-150 | sql_variantデータ。 |
Note
SQL_SS_UDT
SQL_SS_VARIANTはモジュールレベルの属性としてエクスポートされない内部定数です。
-151を呼ぶ際には整数の値(-150、add_output_converter())を直接使います。
setinputsizes()
ドライバの自動型推論が予期せぬ挙動を引き起こす場合、例えばカラムがsetinputsizes()されているがドライバが送信した場合にパラメータ型を明示的に宣言するためにexecutemany()前にvarchar(100)を呼び出しますnvarchar:
Note
小数点については、 SQL_DECIMAL や SQL_NUMERICではなく、ドライバーの自動型推論に頼ってください。 これらの明示的な10進法定数には現在、 setinputsizes()で既知の問題があります。 詳細については、「 クエリ実行」を参照してください。
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),
]
)
小数点の区切り文字
ドライバーは位置認識の小数点区切りを使用します。 カスタマイズするには、次のように実行します。
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(",")
カスタムタイプコンバーター
特定の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)
詳細については、 カスタムタイプコンバーターをご覧ください。
特殊なハンドルタイプ
UUIDの扱い
ドライバーは uuid.UUID を自動的に uniqueidentifier にマッピングします。 手動の文字列変換なしでUUIDの挿入と取得が可能です:
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})
デフォルトでは、ドライバーは UNIQUEIDENTIFIER 列をオブジェクト uuid.UUID として返します。 代わりにpyodbc互換の大文字文字列を返すには、 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()
モジュールレベルの構成については、native_uuidの設定を参照してください。
タイムタイム(タイムゾーン付き)
datetimeoffset 列はタイムゾーン対応のオブジェクト datetime 返します。 オフセット認識値とオフセットナイーブ値の扱いに関するガイダンスについては、 Datetimeハンドリングを参照してください。
cursor.execute("SELECT SYSDATETIMEOFFSET()")
row = cursor.fetchone()
dt = row[0]
print(f"DateTime: {dt}")
print(f"Timezone: {dt.tzinfo}")
空間データ
運転手は空間タイプ(geography、 geometry)を bytesとして返します。 パラメータ文字列は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]
ロウバージョン/タイムスタンプ
SQL Serverのrowversion(旧timestamp)は二値型であり、日付時間ではありません。
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
大きな価値タイプをストリーミング
varchar(max)、nvarchar(max)、またはvarbinary(max)データの挿入または取得時、ドライバはデータをチャンク単位で送信するためにData-at-Execution(DAE)ストリーミングを使用します。
ストリーミングは入力データのサイズ閾値を超えると自動的に起動します:
| データの種類 | ストリーミングしきい値 |
|---|---|
| varchar(max) | > 8,000バイト |
| nvarchar(max) | > 4,000文字 |
| varbinary(max) | > 8,000バイト |
ストリーミングは execute()、 executemany()、そしてすべてのフェッチAPI(fetchone()、 fetchmany()、 fetchall())で動作します。 このドライバーは特別な設定を必要とせず、大きな数値に対して自動的にストリーミング処理を行います。
サポートされていないSQL Serverタイプ
以下のSQL ServerタイプはネイティブのPython型マッピングを持っていません。
| SQL Server の種類 | 地位 |
|---|---|
| json | サポートしていません |
| vector | サポートしていません |
| table | サポートされていません(テーブル値パラメータ) |
ヒント
json SQL Server型は直接サポートされていませんが、JSONデータをnvarchar(max)列に保存し、SQL Server JSON関数(JSON_VALUE、JSON_QUERY、OPENJSON)でクエリすることができます。 パターンや例については JSONデータを参照してください。
以下のタイプは、bytesとしてデータを返しますが、ネイティブのPython型マッピングは持っていません。
| SQL Server の種類 | Python 型 | Notes |
|---|---|---|
| geography | bytes |
WKBフォーマットには .STAsBinary() を使いましょう。 |
| geometry | bytes |
WKBフォーマットには .STAsBinary() を使いましょう。 |
| hierarchyid | bytes |
二元表現。 |
| sql_variant | 場合により異なる | 基礎となるベースタイプに解決します。 |
十進数と浮子数の精度の比較
財務計算、通貨、または四捨五入誤差が許容できない数値など、正確な精度が重要な場合に decimal.Decimal 用いてください。 科学的測定値やセンサー測定値など、おおよその値が許容できる場合にのみ float を使用します。
ドライバーはdecimal.DecimalをSQL Server decimal/numericにマッピングし、最大38桁までの精度を保持します。
floatSQL Server float(64ビットIEEE 754)にマッピングされており、これは丸めアーティファクトを導入することがあります。
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'>
decimal
/
numeric列を取得する際、ドライバーは常にオブジェクトdecimal.Decimal返します。
float
/
real列を取り戻す際に、運転士はPython floatを戻します。
Warning
平等のために float 価値観を比較しないでください。 代わりに許容範囲を使いましょう: abs(a - b) < 0.0001。
ナンピー型バインディング
mssql-pythonドライバはパラメータのSQL型を決定するためにisinstance()チェックを使用します。 numpy整数型(numpy.int64、 numpy.int32、 numpy.int8)はNumPy 2.xでパス isinstance(x, int) できず、バインディング失敗を引き起こします。
numpy.float64が直接機能するのは、Python floatのサブクラスだからです。
numpyの値をパラメータとして渡す前にネイティブPython型に変換してください:
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"])}
)
pandasやnumpyデータを多用する場合は、 Arrowの統合 や pandasの統合 パスを内部で扱う方法を検討してください。