Wiki Python para dados
SQL de dentro do Python (sqlite3)
Banco em memória para testar regra de SQL sem servidor, e parâmetros com ? para nunca montar SQL com texto concatenado.
O sqlite3 vem com o Python. Um banco :memory: nasce e morre com o programa: é o jeito mais barato de testar uma regra de SQL num teste unitário.
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE pedidos (id INTEGER, cliente TEXT, valor REAL)")
con.executemany("INSERT INTO pedidos VALUES (?, ?, ?)",
[(1, "Ana", 230.0), (2, "Ana", 900.0), (3, "Bruno", None)])
for linha in con.execute("SELECT cliente, COUNT(valor), SUM(valor) FROM pedidos GROUP BY cliente ORDER BY cliente"):
print(linha)Saída (conferida)
('Ana', 2, 1130.0)
('Bruno', 0, None)Parâmetro, nunca texto concatenado
O ? manda o valor separado do SQL: aspas no dado não viram código. Montar SQL com f-string é a porta da injeção de SQL.
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE clientes (nome TEXT)")
con.execute("INSERT INTO clientes VALUES (?)", ("D'Ávila",))
nome = "x' OR '1'='1"
print(con.execute("SELECT COUNT(*) FROM clientes WHERE nome = ?", (nome,)).fetchone())
print(con.execute(f"SELECT COUNT(*) FROM clientes WHERE nome = '{nome}'").fetchone())Saída (conferida)
(0,) (1,)
A segunda consulta, montada com f-string, contou uma linha que não tem esse nome: o texto digitado virou parte do SQL (OR '1'='1' é sempre verdadeiro).
- O mesmo vale para Spark SQL:
spark.sql("SELECT * FROM t WHERE id = :id", args={"id": 7})(Spark 3.4+) em vez deformat. - Os exemplos de SQL desta wiki também rodam no SQLite, mas no seu navegador, pelo sql.js.
Fontes
Conhecimento compartilhado pela Genesis Innovation.