Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
SQLite ist die Standarddatenbank für viele Python-Projekte, FastAPI und Flask-Apps. Sie ermöglicht es Ihnen, Ihre Anwendung schnell zu erstellen, indem Sie die Entscheidung über die Datenplattform auf später verschieben. Wenn es Zeit ist, Ihre Anwendung in die Produktion zu bringen, benötigen Sie Unterstützung für gleichzeitige Benutzer, rollenbasierte Sicherheit, hohe Verfügbarkeit, Disaster Recovery und andere Unternehmensfunktionen. Du musst mit dem mssql-python-Treiber auf Microsoft SQL migrieren.
Unterschiede im SQL-Dialekt
Wenn du von SQLite zu Microsoft SQL migrierst, musst du zwei Dinge angehen: deine SQL-Anweisungen für Transact-SQL (T-SQL) umschreiben und deine Daten migrieren.
Die folgende Tabelle ordnet gängige SQLite-Muster ihren Microsoft SQL-Entsprechungen zu:
| SQLite | SQL Server (T-SQL) | Hinweise |
|---|---|---|
INTEGER PRIMARY KEY AUTOINCREMENT |
int IDENTITY(1,1) PRIMARY KEY |
Microsoft SQL verwendet IDENTITY für Autoinkrement. |
TEXT |
nvarchar(255) oder nvarchar(max) |
Geben Sie immer eine Länge an. Verwenden Sie nvarchar für Unicode. |
REAL |
float oder decimal(18,2) |
Verwenden Sie decimal für exakte Werte wie Geldbeträge. |
BLOB |
varbinary(max) |
Dasselbe Verhalten, anderer Name. |
BOOLEAN (gespeichert als INTEGER) |
bit |
Keine der beiden Datenbanken hat einen nativen Boolean. Beide speichern 0/1. |
DATETIME('now') |
GETDATE() oder SYSDATETIME() |
SYSDATETIME() führt zu höherer Präzision. |
LIMIT 10 OFFSET 20 |
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
Erfordert eine ORDER BY Klausel. |
\|\| (Saitenkonkat) |
+ oder CONCAT() |
CONCAT() verarbeitet NULL Werte. |
IFNULL(a, b) |
ISNULL(a, b) oder COALESCE(a, b) |
COALESCE ist ANSI-Standard. |
GROUP_CONCAT(col) |
STRING_AGG(col, ',') |
Verfügbar in SQL Server 2017+. |
INSERT OR REPLACE INTO |
MERGE-Anweisung |
SQLite löscht und fügt wieder ein; MERGE aktualisiert an Ort und Stelle. Siehe das folgende Beispiel. |
last_insert_rowid() |
OUTPUT INSERTED.id |
Verwenden Sie OUTPUT in der Anweisung INSERT.
SCOPE_IDENTITY() Funktioniert auch, erfordert aber einen separaten SELECT. |
typeof(x) |
SQL_VARIANT_PROPERTY(x, 'BaseType') |
Selten nötig bei strenger Typisierung. |
CREATE TABLE Beispiel
-- 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
);
Abfragebeispiele
Paginierung:
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)
)
Die Reihenfolge der Parameter ist umgekehrt. Transact-SQL setzt OFFSET vor FETCH NEXT.
Upsert (Einfügen oder Update):
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))
Die Klausel USING definiert source.[key] und source.value als Spaltenaliase. Die Klauseln WHEN beziehen sich auf diese Aliasnamen. Es werden nur zwei ? Marker benötigt.
Zuletzt eingefügte 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()
Verbindungscode aktualisieren
Ersetzen Sie sqlite3.connect() durch 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;"
)
Der Zugriff auf Zeilen funktioniert ähnlich. Die SQLite-Fabrik Row liefert dict-ähnliche Zeilen mit row["column"] Syntax zurück. Der mssql-python-Treiber liefert Objekte zurück, Row die denselben String-Key-Zugriff sowie Attribut- und Indexzugriff unterstützen:
SQLite (mit row_factory):
row["name"]
mssql-python:
row["name"] # String-key access, like SQLite
row.name # Attribute access
row[0] # Index access
Parameterstil aktualisieren
Sowohl SQLite als auch mssql-python dienen ? als Parametermarker, sodass die meisten Abfragen ohne Änderungen funktionieren.
# Works with both sqlite3 and mssql-python
cursor.execute("SELECT * FROM Production.Product WHERE Name = ?", ("Adjustable Race",))
Der einzige Unterschied: SQLite erlaubt benannte Parameter mit Syntax :name . Der mssql-python-Treiber verwendet %(name)s stattdessen.
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})
Migrierung bestehender Daten
Wichtige Überlegungen bei der Migration von Daten von SQLite zu Microsoft SQL:
- Microsoft SQL speichert nvarchar(max)- und varbinary(max)-Werte als große Objekte (LOBs), die langsamer zu lesen und zu schreiben sind als In-Row-Daten. Halte die String-Spalten auf nvarchar(4000) oder weniger, wann immer deine Daten es zulassen. SQL Server speichert diese Werte direkt in der Datenzeile und vermeidet so den LOB-Overhead.
- Die Typabbildung folgt den Typaffinitätsregeln von SQLite. Überprüfen Sie die generierten Tabellen nach der Migration, um die Spaltengrößen zu verschärfen (zum Beispiel nvarchar(100) statt nvarchar(4000)) oder fügen Sie Einschränkungen hinzu, die SQLite nicht erzwungen hat.
- Für SQLite-Tabellen, die TEXT zur Datenspeicherung verwenden, musst du die Werte möglicherweise vor dem Einfügen in Python-Objekte
datetimeumwandeln. Microsoft SQL erwartet korrekte Datetime-Werte, keine Textzeichen.
Verwenden Sie dieses Skript, um das Schema und die Daten aus SQLite auszulesen und entsprechende Tabellen in Microsoft SQL zu erstellen:
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()
Unterschiede zwischen den Funktionen
Nach der Migration erhält Ihre Anwendung Zugriff auf Microsoft SQL-Funktionen, die SQLite nicht unterstützt:
| Funktion | SQLite | SQL Server |
|---|---|---|
| Gleichzeitige Schreibvorgänge | Einzelne Autorin nach der anderen | Volle Nebenläufigkeit mit Sperrung auf Zeilenebene |
| Authentifizierung | Nur Dateiberechtigungen | SQL-Authentifizierung, Windows-Authentifizierung, Microsoft Entra ID |
| Gespeicherte Prozeduren | Nicht unterstützt | Vollständige T-SQL-Programmierbarkeit |
| Encryption | Nicht eingebaut | TLS unterwegs, TDE in Ruhe |
| Transaktionen | Sicherungspunkte, grundlegende Isolationsstufen | Vollständige Isolationsstufen, verteilte Transaktionen |
| JSON-Unterstützung | json_extract() |
OPENJSON(), JSON_VALUE(), FOR JSON |
| Volltextsuche | FTS5-Erweiterung | Eingebaute Volltextindexierung |
| Max. Datenbankgröße | ~281 TB (praktische Grenze liegt niedriger) | 524 Petabyte |
| Verbindungspooling | N/A (in Bearbeitung) | Eingebaut mit mssql-python |