SQLiteは多くのPythonプロジェクト、FastAPI、Flaskアプリのデフォルトデータベースです。 データプラットフォームの決定を後回しにすることで、アプリケーションを迅速に構築できます。 アプリケーションを本番環境に投入する際には、同時ユーザーのサポート、ロールベースのセキュリティ、高可用性、災害復旧、その他のエンタープライズ機能が必要です。 mssql-pythonドライバーを使ってMicrosoft SQLに移行する必要があります。
SQL方言の違い
SQLiteからMicrosoft SQLに移行する際には、2つのことに対処する必要があります。Transact-SQL 用にSQL文を書き直すこと(T-SQL)とデータの移行です。
以下の表は、一般的なSQLiteパターンをMicrosoftのSQL対応パターンにマッピングしています:
| SQLite | SQL Server (T-SQL) | Notes |
|---|---|---|
INTEGER PRIMARY KEY AUTOINCREMENT |
int IDENTITY(1,1) PRIMARY KEY |
Microsoft SQLは自動増分にIDENTITYを使用します。 |
TEXT |
nvarchar(255) または nvarchar(max) |
必ず長さを指定してください。 Unicodeには nvarchar を使いましょう。 |
REAL |
float または decimal(18,2) |
お金のような正確な価値 decimal 使うのが良いです。 |
BLOB |
varbinary(max) |
同じ行動で、名前が違う。 |
BOOLEAN (整数として保存) |
bit |
どちらのデータベースにもネイティブのブール値は存在しません。 どちらも 0/1を保存しています。 |
DATETIME('now') |
GETDATE() または SYSDATETIME() |
SYSDATETIME() より高い精度をもたらします。 |
LIMIT 10 OFFSET 20 |
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
ORDER BY条項が必要です。 |
\|\|(文字列の連結) |
+ または CONCAT() |
CONCAT()
NULL値を扱います。 |
IFNULL(a, b) |
ISNULL(a, b) または COALESCE(a, b) |
COALESCE ANSI標準です。 |
GROUP_CONCAT(col) |
STRING_AGG(col, ',') |
SQL Server 2017+で利用可能。 |
INSERT OR REPLACE INTO |
MERGE ステートメント |
SQLiteは削除と再挿入を行います。 MERGE アップデートが実施されています。 以下の例を参照してください。 |
last_insert_rowid() |
OUTPUT INSERTED.id |
OUTPUT文でINSERTを使いましょう。
SCOPE_IDENTITY() これも使えますが、別の SELECTが必要です。 |
typeof(x) |
SQL_VARIANT_PROPERTY(x, 'BaseType') |
厳密なタイプ設定ではほとんど必要ありません。 |
CREATE TABLE 例
-- SQLite
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL DEFAULT 0.0,
created_at TEXT DEFAULT (datetime('now')),
is_active BOOLEAN DEFAULT 1
);
-- SQL Server
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'products')
CREATE TABLE products (
id int IDENTITY(1,1) PRIMARY KEY,
name nvarchar(100) NOT NULL,
price decimal(10,2) DEFAULT 0.0,
created_at datetime2 DEFAULT SYSDATETIME(),
is_active bit DEFAULT 1
);
クエリの例
ページ数:
SQLite:
cursor.execute("SELECT * FROM products ORDER BY name LIMIT ? OFFSET ?", (10, 20))
mssql-python:
cursor.execute(
"SELECT * FROM Production.Product ORDER BY Name OFFSET ? ROWS FETCH NEXT ? ROWS ONLY",
(20, 10)
)
パラメータの順序が逆になっています。 Transact-SQL OFFSET を FETCH NEXTより優先します。
アップサート(挿入または更新):
SQLite:
cursor.execute("""
INSERT OR REPLACE INTO settings (key, value)
VALUES (?, ?)
""", (key, value))
mssql-python:
cursor.execute("""
MERGE #Settings AS target
USING (SELECT ? AS [key], ? AS value) AS source
ON target.[key] = source.[key]
WHEN MATCHED THEN UPDATE SET value = source.value
WHEN NOT MATCHED THEN INSERT ([key], value) VALUES (source.[key], source.value);
""", (key, value))
USING節はsource.[key]とsource.valueを列のエイリアスとして定義しています。
WHEN条項はこれらの別名を参照しています。 必要な ? 標は2つだけです。
最終入力ID:
SQLite:
cursor.execute("INSERT INTO products (name) VALUES (?)", ("Widget",))
product_id = cursor.lastrowid
mssql-python:
cursor.execute(
"INSERT INTO #Products (Name) OUTPUT INSERTED.ProductID VALUES (?)",
("Widget",)
)
product_id = cursor.fetchval()
接続コードの更新
sqlite3.connect()をmssql_python.connect()に置き換えます。
SQLite:
import sqlite3
def get_connection():
conn = sqlite3.connect("myapp.db")
conn.row_factory = sqlite3.Row
return conn
mssql-python:
import mssql_python
def get_connection():
return mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
行アクセスも同様に機能します。 SQLiteのRowファクトリは、row["column"]構文でアクセスできる辞書のような行を返します。 mssql-pythonドライバは、同じ文字列キーアクセスに加え、属性およびインデックスアクセスをサポートする Row オブジェクトを返します。
SQLite(row_factory付き):
row["name"]
mssql-python:
row["name"] # String-key access, like SQLite
row.name # Attribute access
row[0] # Index access
パラメータスタイルを更新
SQLiteもmssql-pythonもパラメータマーカーとして ? を使用しているため、ほとんどのクエリは変更なしで動作します。
# Works with both sqlite3 and mssql-python
cursor.execute("SELECT * FROM Production.Product WHERE Name = ?", ("Adjustable Race",))
唯一の違いは、SQLiteが命名済みパラメータを使えば :name 構文を使えることです。 mssql-pythonのドライバーは代わりに %(name)s を使用します。
SQLite:
cursor.execute("SELECT * FROM products WHERE id = :id", {"id": 42})
mssql-python:
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(id)s", {"id": 42})
既存データの移行
SQLiteからMicrosoft SQLへのデータ移行における重要な考慮事項:
- Microsoft SQLはnvarchar(max)およびvarbinary(max)の値を大きなオブジェクト(LOB)として保存しており、行内データよりも読み書きが遅いです。 データが許す限り、文字列の列は nvarchar(4000) 以下に保ちましょう。 SQL Serverはこれらの値を直接データ行に格納し、LOBのオーバーヘッドを回避します。
- 型マッピングはSQLiteの 型親和性ルールに従っています。 移行後に生成されたテーブルを確認し、列サイズを厳しく調整したり(例:nvarchar(4000)ではなくnvarchar(100)に設定したり)、SQLiteで強制されなかった制約を追加したりしましょう。
- SQLite のテーブルで日付の保存に TEXT を使用する場合、挿入する前に値を Python
datetimeオブジェクトに解析する必要があるかもしれません。 Microsoft SQLはテキスト文字列ではなく、適切なdatetime値を期待しています。
このスクリプトを使ってSQLiteのスキーマとデータを読み取り、Microsoft SQLで対応するテーブルを作成します:
import sqlite3
import mssql_python
# SQLite type affinity -> Microsoft SQL type
# Keywords follow SQLite's type affinity rules
TYPE_MAP = {
"INT": "bigint",
"CHAR": "nvarchar(4000)",
"CLOB": "nvarchar(max)",
"TEXT": "nvarchar(4000)",
"BLOB": "varbinary(max)",
"REAL": "float",
"FLOA": "float",
"DOUB": "float",
}
def map_type(sqlite_type: str) -> str:
"""Map a SQLite column type to a Microsoft SQL type."""
upper = (sqlite_type or "TEXT").upper()
for prefix, sql_type in TYPE_MAP.items():
if prefix in upper:
return sql_type
return "decimal(18,6)" # NUMERIC affinity (default)
# Connect to both databases
sqlite_conn = sqlite3.connect("myapp.db")
sql_conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
# Get list of tables from SQLite
sqlite_cur = sqlite_conn.cursor()
sqlite_cur.execute(
"SELECT name FROM sqlite_master "
"WHERE type='table' AND name NOT LIKE 'sqlite_%'"
)
tables = [row[0] for row in sqlite_cur.fetchall()]
sql_cursor = sql_conn.cursor()
for table in tables:
# Read column info from SQLite
sqlite_cur.execute(f"PRAGMA table_info([{table}])")
columns = sqlite_cur.fetchall()
# columns: (cid, name, type, notnull, default_value, pk)
# Build CREATE TABLE statement
col_defs = []
for col in columns:
name, col_type, notnull, pk = col[1], col[2], col[3], col[5]
sql_type = map_type(col_type)
parts = [f"[{name}] {sql_type}"]
if notnull:
parts.append("NOT NULL")
if pk:
parts.append("PRIMARY KEY")
col_defs.append(" ".join(parts))
create_sql = f"CREATE TABLE [{table}] ({', '.join(col_defs)})"
sql_cursor.execute(
f"IF OBJECT_ID('{table}','U') IS NULL " + create_sql
)
sql_conn.commit()
# Read all rows from SQLite
sqlite_cur.execute(f"SELECT * FROM [{table}]")
rows = sqlite_cur.fetchall()
if not rows:
print(f" {table}: created (empty)")
continue
# Use bulkcopy for fast insert
result = sql_cursor.bulkcopy(table, rows)
print(f" {table}: {result['rows_copied']} rows copied")
sql_conn.commit()
sqlite_conn.close()
sql_conn.close()
機能の違い
移行後、あなたのアプリケーションはSQLiteがサポートしないMicrosoft SQL機能にアクセスできます:
| 特徴 | SQLite | SQL Server |
|---|---|---|
| 同時書き込み | 一度に一人の作家を | 行レベルロックによる完全並行処理 |
| Authentication | ファイル権限のみ | SQL 認証、Windows 認証、Microsoft Entra ID |
| ストアド プロシージャ | サポートしていません | 完全なT-SQLプログラマビリティ |
| Encryption | 内蔵ではありません | TLSは移動中、TDEは静止中 |
| Transactions | セーブポイント、基本的な隔離レベル | 完全な隔離レベル、分散トランザクション |
| JSON のサポート | json_extract() |
OPENJSON()、JSON_VALUE()、FOR JSON |
| フルテキスト検索 | FTS5拡張 | 組み込みの全文インデックス作成 |
| 最大データベース サイズ | ~281TB(実用的な上限下) | 524 ペタバイト (PB) |
| コネクションプーリング | N/A(進行中) | mssql-pythonに組み込み |