Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
SQLite é o banco de dados padrão para muitos projetos Python, FastAPI e aplicativos Flask. Ele permite que você construa sua aplicação rapidamente adiando a decisão da plataforma de dados para depois. Quando chegar a hora de levar sua aplicação para produção, você precisa de suporte para usuários concorrentes, segurança baseada em funções, alta disponibilidade, recuperação de desastres e outros recursos corporativos. Você precisa migrar para Microsoft SQL usando o driver mssql-python.
Diferenças no diaaleto SQL
Quando você migra do SQLite para o Microsoft SQL, precisa resolver duas coisas: reescrever suas instruções SQL para Transact-SQL (T-SQL) e migrar seus dados.
A tabela a seguir mapeia padrões comuns do SQLite para seus equivalentes em Microsoft SQL:
| SQLite | SQL Server (T-SQL) | Notes |
|---|---|---|
INTEGER PRIMARY KEY AUTOINCREMENT |
int IDENTITY(1,1) PRIMARY KEY |
O Microsoft SQL usa IDENTITY para autoincremento. |
TEXT |
nvarchar(255) ou nvarchar(max) |
Sempre especifique um comprimento. Use nvarchar para Unicode. |
REAL |
float ou decimal(18,2) |
Use decimal para valores exatos, como dinheiro. |
BLOB |
varbinary(max) |
Mesmo comportamento, nome diferente. |
BOOLEAN (armazenado como INTEGER) |
bit |
Nenhum dos dois bancos de dados possui um booleano nativo. Ambos armazenam 0/1. |
DATETIME('now') |
GETDATE() ou SYSDATETIME() |
SYSDATETIME() Dá maior precisão. |
LIMIT 10 OFFSET 20 |
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
Exige uma ORDER BY cláusula. |
\|\| (concat de string) |
+ ou CONCAT() |
CONCAT() lida com valores NULL. |
IFNULL(a, b) |
ISNULL(a, b) ou COALESCE(a, b) |
COALESCE é padrão ANSI. |
GROUP_CONCAT(col) |
STRING_AGG(col, ',') |
Disponível no SQL Server 2017+. |
INSERT OR REPLACE INTO |
Instrução MERGE |
SQLite exclui e reinsere; MERGE atualiza no local. Veja o exemplo a seguir. |
last_insert_rowid() |
OUTPUT INSERTED.id |
Use OUTPUT na INSERT declaração.
SCOPE_IDENTITY() também funciona, mas requer um arquivo separado SELECT. |
typeof(x) |
SQL_VARIANT_PROPERTY(x, 'BaseType') |
Raramente necessário com digitação rigorosa. |
CREATE TABLE exemplo
-- 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
);
Exemplos de consulta
Paginação:
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)
)
A ordem dos parâmetros é invertida. Transact-SQL põe OFFSET antes FETCH NEXTde .
Upsert (inserir ou atualizar):
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))
A USING cláusula define source.[key] e source.value como aliases de coluna. As WHEN cláusulas fazem referência a esses apelidos. São necessários apenas dois ? marcadores.
Último ID inserido:
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()
Atualizar código de conexão
Substitua sqlite3.connect() por 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;"
)
O acesso à linha funciona de forma semelhante. O factory do Row SQLite retorna linhas semelhantes a dicionários com a sintaxe row["column"]. O driver mssql-python retorna objetos Row que suportam o mesmo tipo de acesso por chave de string, além de acesso por atributo e por índice:
SQLite (com row_factory):
row["name"]
MSSQL-Python:
row["name"] # String-key access, like SQLite
row.name # Attribute access
row[0] # Index access
Estilo de parâmetro de atualização
Tanto o SQLite quanto o mssql-python usam ? como marcador de parâmetro, então a maioria das consultas funciona sem alterações.
# Works with both sqlite3 and mssql-python
cursor.execute("SELECT * FROM Production.Product WHERE Name = ?", ("Adjustable Race",))
A única diferença: SQLite permite parâmetros nomeados com :name sintaxe. O driver mssql-python usa %(name)s em vez disso.
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})
Migrar dados existentes
Considerações importantes ao migrar dados do SQLite para o Microsoft SQL:
- O Microsoft SQL armazena os valores nvarchar(max) e varbinary(max) como objetos grandes (LOBs), que são mais lentos para ler e gravar do que os dados em linha. Mantenha as colunas de texto em nvarchar(4000) ou inferior sempre que os seus dados permitirem. O SQL Server armazena esses valores diretamente na linha de dados, evitando a sobrecarga do LOB.
- O mapeamento de tipos segue as regras de afinidade de tipos do SQLite. Revise as tabelas geradas após a migração para apertar o tamanho das colunas (por exemplo, nvarchar(100) em vez de nvarchar(4000)) ou adicionar restrições que o SQLite não aplicou.
- Para tabelas SQLite que usam TEXT para armazenar datas, talvez seja necessário analisar os valores em objetos Python
datetimeantes de inserir. O Microsoft SQL espera valores corretos de data-hora, não strings de texto.
Use este script para ler o esquema e os dados do SQLite e criar tabelas correspondentes no 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()
Diferenças entre funcionalidades
Após a migração, seu aplicativo ganha acesso a recursos do Microsoft SQL que o SQLite não suporta:
| Característica | SQLite | SQL Server |
|---|---|---|
| Gravações simultâneas | Escritor único por vez | Concorrência total com bloqueio em nível de linha |
| Authentication | Apenas permissões de arquivo | autenticação SQL, autenticação do Windows, Microsoft Entra ID |
| Procedimentos armazenados | Sem suporte | Programabilidade total em T-SQL |
| Encryption | Não integrado | TLS em trânsito, TDE em repouso |
| Transactions | Pontos de salvamento, níveis básicos de isolamento | Níveis de isolamento total, transações distribuídas |
| Suporte a JSON | json_extract() |
OPENJSON(), JSON_VALUE(), FOR JSON |
| Pesquisa de texto completo | Extensão FTS5 | Indexação de texto completo embutida |
| Tamanho máximo do banco de dados | ~281 TB (limite prático menor) | 524 Petabytes |
| Agrupamento de conexões | N/A (em processo) | Integrado ao mssql-python |