Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
SQLite to domyślna baza danych dla wielu projektów Python, FastAPI i aplikacji Flapsk. Pozwala to szybko zbudować aplikację, odkładając decyzję o platformie danych na później. Gdy przyjdzie czas na uruchomienie aplikacji produkcyjnej, potrzebujesz wsparcia dla jednoczesnych użytkowników, bezpieczeństwa opartego na rolach, wysokiej dostępności, odzyskiwania po awarii i innych funkcji korporacyjnych. Musisz przejść do Microsoft SQL za pomocą sterownika mssql-python.
Różnice w dialekcie SQL
Podczas migracji z SQLite do Microsoft SQL musisz zająć się dwoma rzeczami: przepisać swoje instrukcje SQL dla Transact-SQL (T-SQL) oraz przeprowadzić migrację danych.
Poniższa tabela mapuje typowe wzorce SQLite na ich odpowiedniki Microsoft SQL:
| SQLite | SQL Server (T-SQL) | Notatki |
|---|---|---|
INTEGER PRIMARY KEY AUTOINCREMENT |
int IDENTITY(1,1) PRIMARY KEY |
Microsoft SQL używa IDENTITY do automatycznego zwiększania. |
TEXT |
nvarchar(255) lub nvarchar(max) |
Zawsze określaj długość. Zastosowanie nvarchar w Unicode. |
REAL |
float lub decimal(18,2) |
Użyj decimal dla dokładnych wartości, takich jak pieniądze. |
BLOB |
varbinary(max) |
To samo zachowanie, inne imię. |
BOOLEAN (przechowywane jako INTEGER) |
bit |
Żadna z baz danych nie posiada natywnego booleana. Oba przechowują 0/1. |
DATETIME('now') |
GETDATE() lub SYSDATETIME() |
SYSDATETIME() Daje większą precyzję. |
LIMIT 10 OFFSET 20 |
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
Wymaga klauzuli ORDER BY . |
\|\| (struna konkata) |
+ lub CONCAT() |
CONCAT() obsługuje NULL wartości. |
IFNULL(a, b) |
ISNULL(a, b) lub COALESCE(a, b) |
COALESCE jest standardem ANSI. |
GROUP_CONCAT(col) |
STRING_AGG(col, ',') |
Dostępny w SQL Server 2017+. |
INSERT OR REPLACE INTO |
MERGE, oświadczenie |
SQLite usuwa i wstawia ponownie; MERGE aktualizuje na miejscu. Zobacz następujący przykład. |
last_insert_rowid() |
OUTPUT INSERTED.id |
Użyj OUTPUT w instrukcji INSERT.
SCOPE_IDENTITY() Też działa, ale wymaga osobnego SELECT. |
typeof(x) |
SQL_VARIANT_PROPERTY(x, 'BaseType') |
Rzadko potrzebne przy ścisłym pisaniu na klawiaturze. |
CREATE TABLE Przykład
-- 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
);
Przykłady zapytań
Paginacja:
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)
)
Kolejność parametrów jest odwrócona. Transact-SQL stawia OFFSET przed FETCH NEXT.
Upsert (wstaw lub zaktualizuj):
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))
Klauzula definiuje USINGsource.[key] i source.value jako aliasy kolumnowe. Klauzule WHEN odnoszą się do tych aliasów. Potrzebne są tylko dwa znaczniki ?.
Ostatni wprowadzony 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()
Zaktualizuj kod połączenia
Zastąp ciąg sqlite3.connect() ciągiem 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;"
)
Dostęp na poziomie wiersza działa podobnie. Fabryka Row SQLite zwraca wiersze podobne do dyktów z row["column"] składnią. Sterownik mssql-python zwraca obiekty Row, które obsługują ten sam dostęp przy użyciu kluczy tekstowych, a także dostęp przez atrybuty i indeksy:
SQLite (z row_factory):
row["name"]
mssql-python:
row["name"] # String-key access, like SQLite
row.name # Attribute access
row[0] # Index access
Styl aktualizacji parametrów
Zarówno SQLite, jak i mssql-python ? używają jako markera parametrów, więc większość zapytań działa bez zmian.
# Works with both sqlite3 and mssql-python
cursor.execute("SELECT * FROM Production.Product WHERE Name = ?", ("Adjustable Race",))
Różnica jest taka: SQLite pozwala na nazwane parametry z :name składnią. Sterownik mssql-python używa zamiast tego %(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})
Migracja istniejących danych
Ważne kwestie przy migracji danych z SQLite do Microsoft SQL:
- Microsoft SQL przechowuje wartości nvarchar(max) i varbinary(max) jako duże obiekty (LOB), które są wolniejsze w odczytie i zapisie niż dane w wierszu. Utrzymuj kolumny ciągów na poziomie nvarchar(4000) lub mniej, kiedy tylko pozwalają na to twoje dane. SQL Server przechowuje te wartości bezpośrednio w wierszu danych, co pozwala uniknąć narzutu LOB.
- Mapowanie typów opiera się na zasadach powinowactwa typów SQLite. Przejrzyj wygenerowane tabele po migracji, aby dopracować rozmiary kolumn (np. nvarchar(100) zamiast nvarchar(4000)) lub dodać ograniczenia, których SQLite nie egzekwował.
- W tabelach SQLite, które używają TEXT-a do przechowywania dat, może być konieczne przetworzenie wartości na obiekty Python
datetimeprzed wstawieniem. Microsoft SQL oczekuje prawidłowych wartości dat, a nie tekstów.
Użyj tego skryptu, aby odczytać schemat i dane z SQLite oraz tworzyć pasujące tabele w 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()
Różnice między funkcjami
Po migracji Twoja aplikacja zyskuje dostęp do funkcji Microsoft SQL, których SQLite nie obsługuje:
| Funkcja | SQLite | SQL Server |
|---|---|---|
| Współbieżne zapisy | Jeden pisarz na raz | Pełna współbieżność z blokowaniem na poziomie wierszy |
| Authentication | Tylko uprawnienia do plików | uwierzytelnianie SQL, uwierzytelnianie systemu Windows, Microsoft Entra ID |
| Procedury przechowywane | Niewspierane | Pełna programowalność T-SQL |
| Encryption | Nie wbudowane | TLS w transporcie, TDE w spoczynku |
| Transakcje | Punkty przywracania, podstawowe poziomy izolacji | Poziomy pełnej izolacji, transakcje rozproszone |
| Obsługa formatu JSON | json_extract() |
OPENJSON(), JSON_VALUE(), FOR JSON |
| Wyszukiwanie pełnotekstowe | Rozszerzenie FTS5 | Wbudowane indeksowanie pełnego tekstu |
| Maksymalny rozmiar bazy danych | ~281 TB (praktyczny limit niższy) | 524 PB |
| Buforowanie połączeń | N/A (w trakcie realizacji) | Wbudowane w mssql-python |