SQLite'den Microsoft SQL'e mssql-python ile geçiş

SQLite, birçok Python projesi, FastAPI ve Flask uygulaması için varsayılan veritabanıdır. Veri platformunun kararını daha sonra erteleyerek uygulamanızı hızlıca oluşturmanıza olanak tanır. Uygulamanızı üretime taşıma zamanı geldiğinde, eşzamanlı kullanıcılar desteği, rol tabanlı güvenlik, yüksek erişilebilirlik, felaket kurtarma ve diğer kurumsal özellikler için destek gerekir. MSSQL-python sürücüsünü kullanarak Microsoft SQL'e geçiş yapmanız gerekiyor.

SQL lehçesi farklılıkları

SQLite'den Microsoft SQL'e geçiş yaparken iki şeyi ele almanız gerekir: Transact-SQL için SQL ifadelerinizi yeniden yazmak (T-SQL) ve verilerinizi taşımak.

Aşağıdaki tablo, yaygın SQLite kalıplarını Microsoft SQL eşdeğerleriyle eşler:

SQLite SQL Server (T-SQL) Notlar
INTEGER PRIMARY KEY AUTOINCREMENT int IDENTITY(1,1) PRIMARY KEY Microsoft SQL, otomatik artırım için IDENTITY kullanır.
TEXT nvarchar(255) veya nvarchar(max) Her zaman bir uzunluk belirtin. Unicode için kullanın nvarchar .
REAL float veya decimal(18,2) decimal Tam değerler için kullanın, örneğin para.
BLOB varbinary(max) Aynı davranış, farklı isim.
BOOLEAN (TAM SAYI olarak saklanıyor) bit Her iki veritabanında da yerel bir boolean yoktur. Her ikisi de 0/1 saklar.
DATETIME('now') GETDATE() veya SYSDATETIME() SYSDATETIME() daha yüksek hassasiyet sağlar.
LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY Bir ORDER BY maddesi gerekli.
\|\| (dize birleştirme) + veya CONCAT() CONCAT() değerleri NULL yönetir.
IFNULL(a, b) ISNULL(a, b) veya COALESCE(a, b) COALESCE ANSI standartıdır.
GROUP_CONCAT(col) STRING_AGG(col, ',') SQL Server 2017+ içinde mevcuttur.
INSERT OR REPLACE INTO MERGE açıklama SQLite siler ve yeniden ekler; MERGE yerinde günceller. Aşağıdaki örneke bakınız.
last_insert_rowid() OUTPUT INSERTED.id INSERT ifadesinde OUTPUT kullanın. SCOPE_IDENTITY() de çalışır, ancak ayrı bir SELECT gerektirir.
typeof(x) SQL_VARIANT_PROPERTY(x, 'BaseType') Sıkı tiplemeyle nadiren ihtiyaç duyulur.

CREATE TABLE Örnek

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

Sorgu örnekleri

Sayfa Sayılaması:

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

Parametre sırası tersine çevrilmiştir. Transact-SQL, OFFSET öğesini FETCH NEXT öğesinden önce yerleştirir.

Upsert (ekle ya da güncelle):

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 yan tümcesi, source.[key] ve source.value öğelerini sütun diğer adları olarak tanımlar. Bu WHEN maddeler bu takma adlara atıfta bulunur. Sadece iki ? işaretleyici yeterlidir.

Son eklenen 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()

Bağlantı kodunu güncelle

sqlite3.connect() değerini mssql_python.connect() ile değiştirin.

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;"
    )

Sıra erişimi de benzer şekilde çalışıyor. SQLite'ın Row satır fabrikası, row["column"] sözdizimine sahip sözlük benzeri satırlar döndürür. mssql-python sürücüsü, aynı dizi anahtarı erişimini destekleyen nesneleri ve ayrıca öznitelik ve indeks erişimini döndürür Row :

SQLite (row_factory ile):

row["name"]

MSSQL-Python:

row["name"]   # String-key access, like SQLite
row.name      # Attribute access
row[0]        # Index access

Parametre stilini güncelleme

Hem SQLite hem de mssql-python parametre işaretçisi olarak kullanılır ? , bu yüzden çoğu sorgu değişiklik olmadan çalışır.

# Works with both sqlite3 and mssql-python
cursor.execute("SELECT * FROM Production.Product WHERE Name = ?", ("Adjustable Race",))

Tek fark: SQLite, adlandırılmış parametrelere ve :name sözdizimi ile izin verir. Bunun yerine mssql-python sürücüsü kullanılır %(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})

Mevcut verileri taşıma

SQLite'den Microsoft SQL'ye veri taşınırken önemli hususlar:

  • Microsoft SQL nvarchar(max) ve varbinary(max) değerleri büyük nesneler (LOB) olarak saklar; bunlar satır içi verilere göre daha yavaş okunur ve yazılır. Veriniz izin verdiğinde dizi sütunlarını nvarchar(4000) veya daha düşük seviyede tutun. SQL Server bu değerleri doğrudan veri satırında saklar, LOB yükünü önler.
  • Tip eşleme, SQLite'ın tip yakınlığı kurallarını takip eder. Göç sonrası oluşturulan tabloları inceleyerek sütun boyutlarını sıkılaştırın (örneğin, nvarchar(4000) yerine nvarchar(100) gibi) veya SQLite'ın uygulamadığı kısıtlamalar ekleyin.
  • Tarihleri METİN ile saklayan SQLite tabloları için, değerleri eklemeden önce Python datetime nesnelerine ayrıştırmanız gerekebilir. Microsoft SQL, metin dizileri değil, doğru tarih saati değerleri bekler.

Bu betikten SQLite'dan şemayı ve verileri okuyup Microsoft SQL'de eşleşen tablolar oluşturabilirsiniz:

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

Özellik farkları

Göç sonrası uygulamanız, SQLite'ın desteklemediği Microsoft SQL özelliklerine erişim sağlar:

Özellik SQLite SQL Server
Eşzamanlı yazma işlemleri Aynı anda tek yazar Tam eşzamanlılık ve sıra seviyesinde kilitleme
Authentication Sadece dosya izinleri SQL kimlik doğrulaması, Windows kimlik doğrulaması, Microsoft Entra ID
Saklanan prosedürler Desteklenmiyor Tam T-SQL programlanabilirliği
Encryption Yerleşik değil TLS yolculukta, TDE harekette
Transactions Geri alma noktaları, temel yalıtım seviyeleri Tam izolasyon seviyeleri, dağıtık işlemler
JSON desteği json_extract() OPENJSON(), JSON_VALUE(), FOR JSON
Tam metin arama FTS5 uzantısı Yerleşik tam metin indeksleme
Maks. veritabanı boyutu ~281 TB (pratik limit daha düşük) 524 PB
Bağlantı havuzlama Yok (süreçte) mssql-python ile yerleşik