Python sqlite3
A Ana guarda o estoque da lojinha num arquivo de texto. Funciona enquanto são dez produtos. Mas quando ela quer saber "quais produtos custam menos de 10 reais?", "quantos itens tenho ao todo?" ou "tire o óleo da lista", o programa precisa ler o arquivo inteiro, procurar, mudar e escrever tudo de novo. Para isso existem os bancos de dados: um lugar feito para guardar muitos dados e responder perguntas sobre eles. E o Python já vem com um banco pronto para usar, o SQLite, pelo módulo sqlite3. Nada para instalar.
- O que é um banco de dados, uma tabela e o SQL, sem precisar saber SQL antes.
- A abrir (e criar) um banco com
sqlite3.connect()e a criar uma tabela. - A gravar dados com
execute()e o marcador?, e a confirmar comcommit(). - A ler o que está gravado com
fetchall(),fetchone()e com umfor. - A mudar e apagar linhas, e a usar
withpara que tudo dê certo ou nada aconteça. - Por que nunca montar o SQL com f-string: o ataque chamado SQL injection.
- Os erros reais: tabela que não existe, número errado de valores, nome repetido, banco fechado.
A ideia: um fichário que responde perguntas
Pense num fichário de cozinha com uma gaveta etiquetada "produtos". Cada ficha da gaveta tem os mesmos campos: nome, preço, quantidade. Um banco de dados é esse fichário, só que guardado num arquivo e com um atendente que entende pedidos como "me traga as fichas com preço menor que 10".
| No fichário | No banco de dados | Na lojinha da Ana |
|---|---|---|
| O fichário inteiro | O banco (no SQLite, um arquivo só) | loja.db |
| Uma gaveta etiquetada | Uma tabela | produtos |
| Os campos de cada ficha | As colunas | nome, preco, quantidade |
| Uma ficha | Uma linha (ou registro) | Arroz 5 kg, 27,90, 12 |
| O pedido ao atendente | Um comando SQL | SELECT nome FROM produtos WHERE preco < 10 |
O SQL (diz-se "ésse-quê-éle") é a língua dos bancos de dados. Nesta aula você vai usar só cinco comandos dela, e cada um vem explicado quando aparece: CREATE TABLE (criar a gaveta), INSERT (pôr uma ficha), SELECT (buscar), UPDATE (mudar) e DELETE (apagar). O Python não entende SQL; quem entende é o SQLite. O papel do sqlite3 é ser a ponte: o Python entrega o texto do comando, o SQLite executa e devolve as respostas como listas e tuplas do Python.
O guia irmão deste, o Guia SQL, ensina a língua do zero, com o próprio SQLite (ele pode ainda não estar no ar quando você ler isto). Aqui o foco é o lado do Python: como conversar com o banco a partir de um programa.
1. Abrindo o banco: connect()
import sqlite3
con = sqlite3.connect("loja.db")
print("Conectei ao banco:", con)
print("Versão do SQLite:", sqlite3.sqlite_version)
con.close()
- import sqlite3
- Traz o módulo da biblioteca padrão (ele vem junto com o Python; veja Módulos e import).
- sqlite3.connect("loja.db")
- "Conectar": abre o banco guardado no arquivo
loja.db. Se o arquivo não existe, ele é criado, vazio. - con
- A conexão: o objeto pelo qual você conversa com o banco. O nome
coné o costume (também se vêconexaoouconn). - sqlite3.sqlite_version
- A versão do SQLite que o seu Python está usando, como texto.
- con.close()
- "Fechar": encerra a conversa com o banco, como fechar um arquivo.
$ python3 conectar.py Conectei ao banco: <sqlite3.Connection object at 0x7f21ea578130> Versão do SQLite: 3.46.1 $ ls -l loja.db -rw-r--r-- 1 ana ana 0 Oct 18 11:45 loja.db
O print(con) mostra só "um objeto de conexão" e um endereço na memória (o 0x7f… muda a cada execução). A versão do SQLite também depende de onde o Python roda: no Ubuntu da Ana é a 3.46.1; no editor do guia aparece 3.39.0, e tudo o que esta aula usa funciona igual nas duas. E o ls -l mostra que o arquivo loja.db apareceu na pasta, com 0 bytes: o banco existe, mas ainda não tem nada dentro.
Em vez de um nome de arquivo, você pode passar o texto especial ":memory:": sqlite3.connect(":memory:"). O banco é criado na memória e some quando o programa termina. É ótimo para testes e exemplos; vários exemplos desta aula usam esse truque.
2. Criando a tabela: CREATE TABLE
Um banco novo é um fichário sem gavetas. Antes de guardar produtos, é preciso criar a tabela, dizendo o nome e o tipo de cada coluna. Para mandar um comando SQL, use con.execute() ("executar") com o comando num texto:
import sqlite3
con = sqlite3.connect("loja.db")
con.execute("""
CREATE TABLE IF NOT EXISTS produtos (
id INTEGER PRIMARY KEY,
nome TEXT NOT NULL UNIQUE,
preco REAL NOT NULL,
quantidade INTEGER NOT NULL
)
""")
con.close()
print("Tabela pronta.")
- """…"""
- Um texto de várias linhas (aspas triplas). O SQL fica mais fácil de ler assim, uma coluna por linha.
- CREATE TABLE IF NOT EXISTS produtos
- "Crie a tabela
produtos, se ela ainda não existir". Sem oIF NOT EXISTS, rodar o programa pela segunda vez daria erro (a tabela já existe). - id INTEGER PRIMARY KEY
- Um número inteiro que identifica cada linha. Como é a "chave primária", o SQLite preenche sozinho: 1, 2, 3…
- nome TEXT NOT NULL UNIQUE
- Texto, obrigatório (
NOT NULL: não pode ficar vazio) e sem repetição (UNIQUE: dois produtos não podem ter o mesmo nome). - preco REAL NOT NULL
- Número com casas decimais (no Python, um
float). - quantidade INTEGER NOT NULL
- Número inteiro (no Python, um
int).
$ python3 criar.py Tabela pronta. $ ls -l loja.db -rw-r--r-- 1 ana ana 12288 Oct 18 11:45 loja.db
O arquivo agora tem 12288 bytes: o SQLite escreveu nele a estrutura da tabela. Você não precisa (nem deve) abrir esse arquivo num editor de texto; ele não é texto, é um formato próprio do SQLite.
| Tipo no SQLite | O que guarda | Volta para o Python como |
|---|---|---|
INTEGER | Números inteiros | int |
REAL | Números com casas decimais | float |
TEXT | Textos | str |
NULL | "Sem valor" | None |
3. Gravando uma linha: INSERT e o marcador ?
import sqlite3
con = sqlite3.connect("loja.db")
con.execute("""
CREATE TABLE IF NOT EXISTS produtos (
id INTEGER PRIMARY KEY,
nome TEXT NOT NULL UNIQUE,
preco REAL NOT NULL,
quantidade INTEGER NOT NULL
)
""")
cur = con.execute(
"INSERT INTO produtos (nome, preco, quantidade) VALUES (?, ?, ?)",
("Arroz 5 kg", 27.90, 12),
)
print("Produto gravado com o id", cur.lastrowid)
con.commit()
con.close()
- INSERT INTO produtos (nome, preco, quantidade)
- "Insira na tabela
produtos, nestas colunas". Oidfica de fora: o SQLite escolhe. - VALUES (?, ?, ?)
- Os valores. Cada
?é um marcador: um lugar vazio que osqlite3preenche com um valor seu. - ("Arroz 5 kg", 27.90, 12)
- Uma tupla com os valores, na mesma ordem dos
?: o primeiro valor vai no primeiro?, e assim por diante. - cur
- O
execute()devolve um cursor, um objeto com o resultado do comando. Aqui você usa só ocur.lastrowid: oidque a linha nova recebeu. - con.commit()
- "Confirmar": grava de verdade no arquivo. Sem ele, a mudança se perde quando a conexão fecha (você vai ver isso acontecer na seção 7).
$ python3 inserir.py Produto gravado com o id 1
Por que os ? em vez de escrever os valores direto no texto? Porque é o sqlite3 quem cuida de pôr cada valor no lugar certo: textos com acento, com apóstrofo (Pão d'água), números com ponto. E, principalmente, por segurança: a seção 9 mostra o que pode acontecer quando o programa cola no SQL um texto digitado pelo usuário.
Vários de uma vez: executemany()
Para gravar uma lista inteira, use executemany() ("executar muitos"): o mesmo comando, uma vez para cada tupla da lista.
import sqlite3
con = sqlite3.connect("loja.db")
# (o mesmo CREATE TABLE IF NOT EXISTS de antes fica aqui)
novos = [
("Feijão 1 kg", 8.49, 30),
("Café 500 g", 18.90, 0),
("Açúcar 1 kg", 4.99, 25),
("Óleo 900 ml", 7.75, 8),
]
cur = con.executemany(
"INSERT INTO produtos (nome, preco, quantidade) VALUES (?, ?, ?)",
novos,
)
print("Linhas gravadas:", cur.rowcount)
con.commit()
con.close()
$ python3 varios.py Linhas gravadas: 4
O cur.rowcount diz quantas linhas o comando afetou. Agora o estoque tem cinco produtos.
4. Lendo: SELECT e fetchall()
Para buscar, o comando SQL é o SELECT ("selecionar"): quais colunas, de qual tabela. O resultado vem no cursor, e fetchall() ("buscar todas") entrega todas as linhas de uma vez.
import sqlite3
con = sqlite3.connect("loja.db")
cur = con.execute("SELECT id, nome, preco, quantidade FROM produtos")
linhas = cur.fetchall()
print(linhas)
print("Tipo:", type(linhas), "com", len(linhas), "linhas")
print("Primeira linha:", linhas[0], type(linhas[0]))
con.close()
$ python3 consultar.py [(1, 'Arroz 5 kg', 27.9, 12), (2, 'Feijão 1 kg', 8.49, 30), (3, 'Café 500 g', 18.9, 0), (4, 'Açúcar 1 kg', 4.99, 25), (5, 'Óleo 900 ml', 7.75, 8)] Tipo: <class 'list'> com 5 linhas Primeira linha: (1, 'Arroz 5 kg', 27.9, 12) <class 'tuple'>
Repare no formato: uma lista de tuplas. Cada tupla é uma linha da tabela, com os valores na ordem das colunas pedidas no SELECT. Os id de 1 a 5 foram preenchidos pelo SQLite. E o preço 27.90 voltou como 27.9: é um float, e o Python não mostra o zero do fim.
Uma linha por vez, com for
O cursor também pode ser percorrido direto num for, sem fetchall(). Cada volta entrega uma tupla, que dá para desempacotar em variáveis:
import sqlite3
con = sqlite3.connect("loja.db")
for id_, nome, preco, quantidade in con.execute(
"SELECT id, nome, preco, quantidade FROM produtos ORDER BY preco DESC"
):
print(f"{id_:>2} {nome:<14} R$ {preco:>6.2f} {quantidade:>3} un.")
con.close()
$ python3 percorrer.py 1 Arroz 5 kg R$ 27.90 12 un. 3 Café 500 g R$ 18.90 0 un. 2 Feijão 1 kg R$ 8.49 30 un. 5 Óleo 900 ml R$ 7.75 8 un. 4 Açúcar 1 kg R$ 4.99 25 un.
O ORDER BY preco DESC pede ao banco as linhas em ordem de preço, do maior para o menor (DESC = decrescente). A formatação com :>6.2f é das f-strings. O nome id_ tem um sublinhado no fim porque id já é o nome de uma função embutida do Python; o sublinhado evita escondê-la.
Uma linha só: fetchone()
Quando a resposta é uma linha só (uma conta, uma busca por id), fetchone() ("buscar uma") devolve a próxima linha, ou None quando não há mais nenhuma:
import sqlite3
con = sqlite3.connect("loja.db")
cur = con.execute("SELECT count(*), sum(quantidade) FROM produtos")
print(cur.fetchone())
cur = con.execute("SELECT nome FROM produtos WHERE quantidade = 0")
print(cur.fetchone())
print(cur.fetchone())
con.close()
$ python3 fetchone.py
(5, 75)
('Café 500 g',)
None
count(*) conta as linhas e sum(quantidade) soma a coluna: 5 produtos, 75 unidades no total. Na segunda busca, o primeiro fetchone() trouxe o único produto sem estoque, numa tupla de um item só (a vírgula em ('Café 500 g',) é o jeito do Python escrever uma tupla de um item). O segundo fetchone() não achou mais nada e devolveu None.
Missão: o programa cria um banco com três produtos, mas não mostra nada. Busque todos os nomes com um SELECT e mostre o resultado (com fetchall() ou com um for).
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE produtos (nome TEXT, preco REAL)")
con.executemany(
"INSERT INTO produtos VALUES (?, ?)",
[("Arroz 5 kg", 27.90), ("Feijão 1 kg", 8.49), ("Café 500 g", 18.90)],
)
# escreva aqui o SELECT e mostre as linhas
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE produtos (nome TEXT, preco REAL)")
con.executemany(
"INSERT INTO produtos VALUES (?, ?)",
[("Arroz 5 kg", 27.90), ("Feijão 1 kg", 8.49), ("Café 500 g", 18.90)],
)
cur = con.execute("SELECT nome FROM produtos")
print(cur.fetchall())
5. Filtrando: WHERE com ?
O WHERE ("onde") filtra as linhas: só vêm as que cumprem a condição. O valor da condição também entra por um ?:
import sqlite3
con = sqlite3.connect("loja.db")
limite = 10.00
cur = con.execute(
"SELECT nome, preco FROM produtos WHERE preco < ? ORDER BY preco",
(limite,),
)
for nome, preco in cur.fetchall():
print(nome, preco)
con.close()
$ python3 filtro.py Açúcar 1 kg 4.99 Óleo 900 ml 7.75 Feijão 1 kg 8.49
(limite,) é obrigatória
Os valores vão sempre numa sequência (tupla ou lista), mesmo quando é um só. (limite,) é uma tupla de um item; (limite), sem a vírgula, é só o valor entre parênteses. Com um número, isso dá erro; com um texto, dá um erro bem estranho, que a seção Quando dá errado explica. Se preferir, use uma lista: [limite].
Marcadores com nome: :nome
Com muitos valores, contar os ? fica difícil. Existe outro estilo: marcadores com nome, escritos :nome, preenchidos por um dicionário:
import sqlite3
con = sqlite3.connect("loja.db")
busca = {"minimo": 5, "maximo": 20}
cur = con.execute(
"SELECT nome, quantidade FROM produtos"
" WHERE quantidade BETWEEN :minimo AND :maximo",
busca,
)
print(cur.fetchall())
con.close()
$ python3 nomeados.py
[('Arroz 5 kg', 12), ('Óleo 900 ml', 8)]
BETWEEN :minimo AND :maximo quer dizer "entre 5 e 20". O :minimo recebe o valor da chave "minimo" do dicionário; a ordem das chaves não importa. (Os dois textos seguidos, sem nada entre eles, o Python junta num só: é um jeito de quebrar um texto comprido em duas linhas.)
6. Mudando e apagando: UPDATE e DELETE
import sqlite3
con = sqlite3.connect("loja.db")
cur = con.execute(
"UPDATE produtos SET quantidade = quantidade + ? WHERE nome = ?",
(20, "Café 500 g"),
)
print("Linhas alteradas:", cur.rowcount)
cur = con.execute("DELETE FROM produtos WHERE nome = ?", ("Óleo 900 ml",))
print("Linhas apagadas:", cur.rowcount)
con.commit()
print(con.execute("SELECT nome, quantidade FROM produtos").fetchall())
con.close()
- UPDATE produtos SET quantidade = quantidade + ?
- "Atualize a tabela: a quantidade passa a ser a quantidade atual mais o valor do
?". Chegaram 20 pacotes de café. - WHERE nome = ?
- Só na linha do café. Sem o
WHERE, oUPDATEmuda todas as linhas da tabela. - DELETE FROM produtos WHERE nome = ?
- "Apague da tabela as linhas onde o nome é…". O mesmo cuidado: sem
WHERE, apaga tudo. - cur.rowcount
- Quantas linhas foram mudadas ou apagadas. Se der 0, nenhuma linha cumpriu o
WHERE(um nome digitado errado, por exemplo), e isso não é erro.
$ python3 atualizar.py
Linhas alteradas: 1
Linhas apagadas: 1
[('Arroz 5 kg', 12), ('Feijão 1 kg', 30), ('Café 500 g', 20), ('Açúcar 1 kg', 25)]
Pegando as colunas pelo nome: sqlite3.Row
Com tuplas, você precisa lembrar que o preço é o item 2. Se mudar con.row_factory ("fábrica de linhas") para sqlite3.Row, cada linha passa a aceitar também o nome da coluna:
import sqlite3
con = sqlite3.connect("loja.db")
con.row_factory = sqlite3.Row
linha = con.execute("SELECT * FROM produtos WHERE id = ?", (1,)).fetchone()
print(linha)
print(linha["nome"], linha["preco"])
print(linha.keys())
print(dict(linha))
con.close()
$ python3 row.py
<sqlite3.Row object at 0x7f12bd3f89d0>
Arroz 5 kg 27.9
['id', 'nome', 'preco', 'quantidade']
{'id': 1, 'nome': 'Arroz 5 kg', 'preco': 27.9, 'quantidade': 12}
O SELECT * quer dizer "todas as colunas". A linha não se mostra bonita no print, mas aceita linha["nome"] (e também linha[1], como uma tupla), sabe os nomes das colunas com keys() e vira um dicionário com dict(linha).
7. commit(): o que acontece se você esquecer
Quando você muda alguma coisa (INSERT, UPDATE, DELETE), o sqlite3 abre uma transação: um pacote de mudanças que ainda está "a lápis". O commit() passa a caneta. Se a conexão fechar sem commit(), o pacote é jogado fora:
import sqlite3
con = sqlite3.connect("loja.db")
con.execute(
"INSERT INTO produtos (nome, preco, quantidade) VALUES (?, ?, ?)",
("Macarrão 500 g", 5.29, 40),
)
print("Antes de fechar:", con.execute("SELECT count(*) FROM produtos").fetchone())
con.close() # esqueci o commit!
con = sqlite3.connect("loja.db")
print("Depois de abrir de novo:", con.execute("SELECT count(*) FROM produtos").fetchone())
con.close()
$ python3 sem_commit.py Antes de fechar: (5,) Depois de abrir de novo: (4,)
Dentro da mesma conexão, o macarrão aparecia (5 produtos). Depois de fechar e abrir de novo, sumiu (4 produtos). Nenhuma mensagem de erro: é o tipo de engano que só se descobre no dia seguinte. A regra: mudou alguma coisa, chame commit(). E existe o contrário do commit(): o con.rollback() ("voltar atrás") descarta de propósito as mudanças ainda não confirmadas.
O jeito mais seguro: with con:
Usar a conexão num bloco with faz o trabalho por você: se o bloco termina bem, ele chama commit(); se acontece um erro no meio, ele chama rollback(), e nenhuma mudança do bloco fica gravada. Tudo ou nada.
import sqlite3
con = sqlite3.connect("loja.db")
with con:
con.execute(
"INSERT INTO produtos (nome, preco, quantidade) VALUES (?, ?, ?)",
("Macarrão 500 g", 5.29, 40),
)
print("Gravado:", con.execute("SELECT count(*) FROM produtos").fetchone())
try:
with con:
con.execute("UPDATE produtos SET quantidade = 0")
con.execute(
"INSERT INTO produtos (nome, preco, quantidade) VALUES (?, ?, ?)",
("Arroz 5 kg", 29.90, 5), # esse nome já existe: UNIQUE
)
except sqlite3.IntegrityError as erro:
print("Deu erro:", erro)
print(con.execute("SELECT sum(quantidade) FROM produtos").fetchone())
con.close()
$ python3 com_with.py Gravado: (5,) Deu erro: UNIQUE constraint failed: produtos.nome (127,)
- O primeiro
with con:gravou o macarrão e confirmou sozinho: agora são 5 produtos. - No segundo, o
UPDATEsemWHEREzerou o estoque de todos os produtos (a lápis). - Logo depois, o
INSERTfalhou: já existe um "Arroz 5 kg" e a colunanomeéUNIQUE. - O
withviu o erro e desfez o bloco inteiro, inclusive oUPDATE. O erro seguiu adiante e foi tratado pelotry/except. - A soma do estoque continua 127 (12 + 30 + 20 + 25 + 40): nada foi zerado.
with con: não fecha a conexão
Diferente do with open(...) dos arquivos, o with da conexão cuida só da transação (commit ou rollback). Depois do bloco, a conexão continua aberta:
import sqlite3
with sqlite3.connect("loja.db") as con:
print(con.execute("SELECT count(*) FROM produtos").fetchone())
print(con.execute("SELECT 'a conexão continua aberta'").fetchone())
con.close()
print(con.execute("SELECT 1").fetchone())
$ python3 with_nao_fecha.py
(5,)
('a conexão continua aberta',)
Traceback (most recent call last):
File "/home/ana/with_nao_fecha.py", line 8, in <module>
print(con.execute("SELECT 1").fetchone())
~~~~~~~~~~~^^^^^^^^^^^^
sqlite3.ProgrammingError: Cannot operate on a closed database.
Só depois do con.close() ela fechou, e usar a conexão fechada deu ProgrammingError: "não dá para operar num banco fechado". Para fechar sozinho, há o closing(), logo abaixo.
Formas de abrir, confirmar e fechar
As três formas abaixo gravam a mesma mudança. A diferença está no que acontece quando algo dá errado.
con = sqlite3.connect("loja.db")
con.execute("UPDATE produtos SET preco = ? WHERE nome = ?", (8.99, "Feijão 1 kg"))
con.commit()
con.close()
con = sqlite3.connect("loja.db")
with con:
con.execute("UPDATE produtos SET preco = ? WHERE nome = ?", (8.99, "Feijão 1 kg"))
con.close()
import sqlite3
from contextlib import closing
with closing(sqlite3.connect("loja.db")) as con:
with con:
con.execute("UPDATE produtos SET preco = ? WHERE nome = ?", (8.99, "Feijão 1 kg"))
print(con.execute("SELECT nome, preco FROM produtos WHERE id = 2").fetchone())
$ python3 closing.py
('Feijão 1 kg', 8.99)
O closing() ("fechando"), do módulo contextlib, chama close() no fim do bloco de fora, aconteça o que acontecer. O with con: de dentro cuida do commit. (Os dois tipos de with são explicados na aula Gerenciadores de Contexto.)
| Forma | Se der erro no meio | Quando usar |
|---|---|---|
commit() e close() à mão | A conexão pode ficar aberta e a transação pela metade | Programas bem curtos, para aprender |
with con: + close() | Desfaz tudo do bloco (rollback) | O jeito do dia a dia para gravar |
closing(...) + with con: | Desfaz o bloco e fecha a conexão | Programas maiores, que não podem deixar nada aberto |
Missão: grave os três produtos da lista chegaram na tabela, com executemany() e marcadores ?, dentro de um with con:. O programa já mostra o total no fim.
import sqlite3
con = sqlite3.connect("estoque.db")
con.execute("CREATE TABLE IF NOT EXISTS produtos (nome TEXT, quantidade INTEGER)")
chegaram = [("Leite 1 L", 24), ("Pão de forma", 15), ("Manteiga 200 g", 28)]
# grave aqui os produtos da lista chegaram
total = con.execute("SELECT sum(quantidade) FROM produtos").fetchone()[0]
print("Total em estoque:", total)
con.close()
import sqlite3
con = sqlite3.connect("estoque.db")
con.execute("CREATE TABLE IF NOT EXISTS produtos (nome TEXT, quantidade INTEGER)")
chegaram = [("Leite 1 L", 24), ("Pão de forma", 15), ("Manteiga 200 g", 28)]
with con:
con.executemany("INSERT INTO produtos VALUES (?, ?)", chegaram)
total = con.execute("SELECT sum(quantidade) FROM produtos").fetchone()[0]
print("Total em estoque:", total)
con.close()
Antes de gravar, o sum() de uma tabela vazia dá None ("Total em estoque: None"). O [0] depois do fetchone() pega o primeiro (e único) valor da tupla.
8. Onde ver o banco por fora
O Python traz também uma "linha de comando" do SQLite: python3 -m sqlite3 arquivo.db abre o banco e deixa você digitar SQL direto, sem escrever programa. Bom para espiar o que o seu programa gravou:
$ python3 -m sqlite3 loja.db
sqlite3 shell, running on SQLite version 3.46.1
Connected to 'loja.db'
Each command will be run using execute() on the cursor.
Type ".help" for more information; type ".quit" or CTRL-D to quit.
sqlite> SELECT nome, quantidade FROM produtos;
('Arroz 5 kg', 12)
('Feijão 1 kg', 30)
('Café 500 g', 20)
('Açúcar 1 kg', 25)
('Macarrão 500 g', 40)
sqlite> .quit
As respostas aparecem como tuplas do Python, porque é o próprio sqlite3 quem roda cada comando. O .quit sai. (Essa linha de comando existe desde o Python 3.12. No 3.15, ela ganhou cores e passou a completar os comandos SQL com a tecla Tab; veja as Novidades.)
9. Nunca monte o SQL com f-string: SQL injection
Parece tão prático escrever f"... WHERE nome = '{nome}'". O problema aparece quando o nome vem de fora do programa: de um input(), de um formulário, de um arquivo. Quem digita pode escrever, em vez de um nome, um pedaço de SQL, e o banco vai obedecer. Esse ataque se chama SQL injection ("injeção de SQL"). Veja com um banco de clientes, com senha e saldo:
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE clientes (nome TEXT, senha TEXT, saldo REAL)")
con.executemany(
"INSERT INTO clientes VALUES (?, ?, ?)",
[("Ana", "gato123", 150.0), ("Bruno", "sol2026", 980.5), ("Carla", "abc", 40.0)],
)
def buscar_errado(nome):
sql = f"SELECT nome, saldo FROM clientes WHERE nome = '{nome}'"
print("SQL montado:", sql)
return con.execute(sql).fetchall()
def buscar_certo(nome):
return con.execute(
"SELECT nome, saldo FROM clientes WHERE nome = ?", (nome,)
).fetchall()
print(buscar_errado("Ana"))
print(buscar_errado("x' OR '1'='1"))
print("---")
print(buscar_certo("Ana"))
print(buscar_certo("x' OR '1'='1"))
$ python3 injecao.py
SQL montado: SELECT nome, saldo FROM clientes WHERE nome = 'Ana'
[('Ana', 150.0)]
SQL montado: SELECT nome, saldo FROM clientes WHERE nome = 'x' OR '1'='1'
[('Ana', 150.0), ('Bruno', 980.5), ('Carla', 40.0)]
---
[('Ana', 150.0)]
[]
- Com o nome
Ana, a f-string montou um SQL normal, e veio só a Ana. - Com o "nome"
x' OR '1'='1, o apóstrofo depois doxfechou o texto antes da hora, e o resto virou parte do comando:WHERE nome = 'x' OR '1'='1', ou seja, "onde o nome é x ou 1 é igual a 1". Como 1 é sempre igual a 1, a condição vale para todas as linhas. - Resultado: o programa mostrou o saldo de todos os clientes para quem digitou aquilo.
- Com o
?, o mesmo texto foi tratado como um nome, letra por letra. Ninguém se chamax' OR '1'='1, então a busca não achou nada ([]). O valor nunca vira comando.
DROP TABLE?
O ataque clássico tenta encaixar um segundo comando, que apaga a tabela inteira (DROP TABLE = "jogue fora a tabela"):
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE clientes (nome TEXT)")
nome = "Ana'; DROP TABLE clientes; --"
con.execute(f"SELECT * FROM clientes WHERE nome = '{nome}'")
$ python3 injecao_drop.py
Traceback (most recent call last):
File "/home/ana/injecao_drop.py", line 6, in <module>
con.execute(f"SELECT * FROM clientes WHERE nome = '{nome}'")
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.ProgrammingError: You can only execute one statement at a time.
"Você só pode executar um comando por vez." O execute() do sqlite3 recusa dois comandos num texto só, e desta vez a tabela escapou. Não conte com isso: o ataque do OR '1'='1', que é um comando só, passou sem erro nenhum, e outros bancos e bibliotecas aceitam vários comandos de uma vez. A proteção de verdade é uma só: valores sempre por ? (ou :nome).
| Pode | Nunca |
|---|---|
con.execute("... WHERE nome = ?", (nome,)) | con.execute(f"... WHERE nome = '{nome}'") |
con.execute("... WHERE nome = :nome", {"nome": nome}) | con.execute("... WHERE nome = '" + nome + "'") |
con.execute("... WHERE nome = '%s'" % nome) |
O ? serve para valores (um nome, um preço, uma data). Ele não serve para o nome de uma tabela ou de uma coluna; esses ficam escritos no próprio SQL do programa, nunca vindos do usuário. A aula SQL Injection do Guia SQL mostra o ataque com mais detalhes, e a aula Parâmetros mostra os marcadores do lado do banco.
Missão: o programa busca o telefone pelo nome digitado, mas monta o SQL com f-string, e quem digita x' OR '1'='1 (já está no teclado da caixa) vê a agenda inteira. Troque a f-string por um marcador ?. Com o conserto, essa "busca" não acha ninguém: [].
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE agenda (nome TEXT, telefone TEXT)")
con.executemany(
"INSERT INTO agenda VALUES (?, ?)",
[("Ana", "86 99999-0001"), ("Bia", "86 99999-0002"), ("Caio", "86 99999-0003")],
)
procurado = input("Nome: ")
cur = con.execute(f"SELECT nome, telefone FROM agenda WHERE nome = '{procurado}'")
print(cur.fetchall())
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE agenda (nome TEXT, telefone TEXT)")
con.executemany(
"INSERT INTO agenda VALUES (?, ?)",
[("Ana", "86 99999-0001"), ("Bia", "86 99999-0002"), ("Caio", "86 99999-0003")],
)
procurado = input("Nome: ")
cur = con.execute("SELECT nome, telefone FROM agenda WHERE nome = ?", (procurado,))
print(cur.fetchall())
Quando dá errado
import sqlite3
con = sqlite3.connect("lojs.db") # o nome certo era loja.db
cur = con.execute("SELECT nome FROM produtos")
$ python3 erro_tabela.py
Traceback (most recent call last):
File "/home/ana/erro_tabela.py", line 4, in <module>
cur = con.execute("SELECT nome FROM produtos")
sqlite3.OperationalError: no such table: produtos
$ ls *.db
loja.db
lojs.db
- Traceback (most recent call last):
- "Rastro (a chamada mais recente por último)": o caminho até o erro. Leia de baixo para cima.
- File "/home/ana/erro_tabela.py", line 4
- O arquivo e a linha onde o erro aconteceu: a linha do
SELECT. - sqlite3.OperationalError
- O tipo do erro: um erro de "operação" do banco. O nome começa com
sqlite3.porque é uma exceção do módulo. - no such table: produtos
- "Não existe a tabela
produtos."
Mas a tabela existe… no loja.db! O nome do arquivo foi digitado errado (lojs.db), e o connect(), em vez de reclamar, criou um banco novo e vazio com esse nome. O ls mostra o intruso. Como consertar: confira o nome do arquivo (e apague o lojs.db que sobrou). Se o arquivo está certo, confira o nome da tabela, ou se o programa que a cria rodou antes.
? diferente do número de valores
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE produtos (nome TEXT, preco REAL, quantidade INTEGER)")
con.execute(
"INSERT INTO produtos VALUES (?, ?, ?)",
("Arroz 5 kg", 27.90),
)
$ python3 erro_bindings.py
Traceback (most recent call last):
File "/home/ana/erro_bindings.py", line 5, in <module>
con.execute(
~~~~~~~~~~~^
"INSERT INTO produtos VALUES (?, ?, ?)",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
("Arroz 5 kg", 27.90),
^^^^^^^^^^^^^^^^^^^^^^
)
^
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 3, and there are 2 supplied.
"Número incorreto de valores. O comando usa 3, e foram dados 2." Os ^^^^ marcam a chamada inteira, que ocupa várias linhas. Um ProgrammingError é um erro "de programação": o banco nem chegou a rodar o comando. Como consertar: um valor para cada ?; aqui faltou a quantidade.
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE produtos (nome TEXT)")
con.execute("SELECT * FROM produtos WHERE nome = ?", ("Arroz"))
$ python3 erro_tupla.py
Traceback (most recent call last):
File "/home/ana/erro_tupla.py", line 5, in <module>
con.execute("SELECT * FROM produtos WHERE nome = ?", ("Arroz"))
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 5 supplied.
"O comando usa 1, e foram dados 5"? Cinco? Sem a vírgula, ("Arroz") não é uma tupla, é só o texto "Arroz". E um texto também é uma sequência: de letras. O sqlite3 contou as letras A, r, r, o, z: cinco valores. Como consertar: ("Arroz",), com a vírgula, ou ["Arroz"].
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE produtos (nome TEXT UNIQUE, preco REAL)")
con.execute("INSERT INTO produtos VALUES (?, ?)", ("Arroz 5 kg", 27.90))
con.execute("INSERT INTO produtos VALUES (?, ?)", ("Arroz 5 kg", 29.90))
$ python3 erro_unique.py
Traceback (most recent call last):
File "/home/ana/erro_unique.py", line 6, in <module>
con.execute("INSERT INTO produtos VALUES (?, ?)", ("Arroz 5 kg", 29.90))
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.IntegrityError: UNIQUE constraint failed: produtos.nome
"A regra UNIQUE falhou: produtos.nome." Um IntegrityError ("erro de integridade") quer dizer que o banco recusou o dado para proteger as regras da tabela. Esse erro é esperado num programa de verdade (alguém sempre tenta cadastrar duas vezes), então vale tratá-lo com try/except sqlite3.IntegrityError, como na seção 7. O mesmo acontece se você rodar o inserir.py da seção 3 pela segunda vez.
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("SELEC 1")
$ python3 erro_sintaxe.py
Traceback (most recent call last):
File "/home/ana/erro_sintaxe.py", line 4, in <module>
con.execute("SELEC 1")
~~~~~~~~~~~^^^^^^^^^^^
sqlite3.OperationalError: near "SELEC": syntax error
"Perto de SELEC: erro de sintaxe." Repare: não é um SyntaxError do Python. Para o Python, "SELEC 1" é um texto como outro qualquer; quem não entendeu foi o SQLite, na hora de executar. O near "…" aponta o trecho onde o SQLite se perdeu.
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE produtos (nome TEXT, preco REAL)")
con.execute("INSERT INTO produtos VALUES (:nome, :preco)", ("Arroz 5 kg", 27.90))
$ python3 erro_nomeado.py
Traceback (most recent call last):
File "/home/ana/erro_nomeado.py", line 5, in <module>
con.execute("INSERT INTO produtos VALUES (:nome, :preco)", ("Arroz 5 kg", 27.90))
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.ProgrammingError: Binding 1 (':nome') is a named parameter, but you supplied a sequence which requires nameless (qmark) placeholders.
"O valor 1 (:nome) é um marcador com nome, mas você deu uma sequência, que pede marcadores sem nome (?)." Como consertar: marcadores :nome pedem um dicionário ({"nome": "Arroz 5 kg", "preco": 27.90}); uma tupla pede ?.
Até o Python 3.13 (o do Debian 13, por exemplo), esse último caso só dava um aviso (DeprecationWarning) e o programa seguia; a partir do 3.14 virou erro. E o 3.14 tirou do módulo o sqlite3.version: para saber a versão, use sqlite3.sqlite_version, como na seção 1.
Missão: a Ana quer o telefone da Bia, mas o programa dá erro. Leia a mensagem e conserte.
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE agenda (nome TEXT, telefone TEXT)")
contatos = [("Ana", "86 99999-0001"), ("Bia", "86 99999-0002"), ("Caio", "86 99999-0003")]
con.executemany("INSERT INTO agenda VALUES (?, ?)", contatos)
procurado = "Bia"
print(con.execute("SELECT telefone FROM agenda WHERE nome = ?", (procurado)).fetchone())
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE agenda (nome TEXT, telefone TEXT)")
contatos = [("Ana", "86 99999-0001"), ("Bia", "86 99999-0002"), ("Caio", "86 99999-0003")]
con.executemany("INSERT INTO agenda VALUES (?, ?)", contatos)
procurado = "Bia"
print(con.execute("SELECT telefone FROM agenda WHERE nome = ?", (procurado,)).fetchone())
Referência rápida
| Escrita | O que faz |
|---|---|
con = sqlite3.connect("loja.db") | Abre o banco do arquivo (cria se não existir) |
sqlite3.connect(":memory:") | Banco temporário, na memória |
con.execute(sql, valores) | Roda um comando SQL; devolve um cursor |
con.executemany(sql, lista) | Roda o mesmo comando para cada tupla da lista |
"... WHERE nome = ?", (nome,) | Marcador ?: valores numa tupla ou lista, na ordem |
"... WHERE nome = :nome", {"nome": nome} | Marcador com nome: valores num dicionário |
cur.fetchall() | Todas as linhas (lista de tuplas) |
cur.fetchone() | A próxima linha (tupla), ou None |
for linha in cur: | Percorre as linhas uma por uma |
cur.lastrowid / cur.rowcount | O id da última linha inserida / quantas linhas o comando afetou |
con.commit() / con.rollback() | Confirma / desfaz as mudanças pendentes |
with con: | Commit se o bloco der certo, rollback se der erro (não fecha) |
con.row_factory = sqlite3.Row | Linhas que aceitam linha["coluna"] |
con.close() / closing(con) | Fecha a conexão / fecha no fim do with |
python3 -m sqlite3 loja.db | Abre o banco para digitar SQL no terminal |
| Erro | Causa provável |
|---|---|
OperationalError: no such table: … | Nome da tabela errado, tabela não criada, ou nome do arquivo do banco errado (o connect criou outro, vazio) |
OperationalError: near "…": syntax error | SQL escrito errado |
ProgrammingError: Incorrect number of bindings supplied | Número de ? diferente do número de valores; ou faltou a vírgula de (valor,) |
ProgrammingError: Binding 1 (':…') is a named parameter… | Marcadores :nome com uma tupla: use um dicionário |
ProgrammingError: You can only execute one statement at a time. | Dois comandos SQL num execute() (às vezes, sinal de SQL injection) |
ProgrammingError: Cannot operate on a closed database. | Usou a conexão depois do close() |
IntegrityError: UNIQUE constraint failed: … | Valor repetido numa coluna UNIQUE |
| Os dados somem, sem erro | Faltou o commit() |
Exercícios
1. Confirmando
Depois de um INSERT, qual método da conexão grava as mudanças de verdade no arquivo? Complete:
2. Um valor só
Complete a tupla de um valor só para buscar o produto de id 3:
3. A Ana escreveu con.execute(f"SELECT * FROM clientes WHERE nome = '{nome}'"), com o nome vindo de um input(). Qual é o problema?
4. O que cur.fetchall() devolve para um SELECT nome, preco que encontrou duas linhas?
5. Dentro de um with con:, o segundo de dois comandos dá erro. O que acontece com o primeiro?
6. sqlite3.connect("clientes.db") numa pasta onde esse arquivo não existe:
Missão final: o caixa da padaria
Missão: a padaria do bairro guarda o estoque num banco. Hoje vendeu 30 pães franceses e 12 sonhos. Complete a função vender(): ela deve tirar a quantidade vendida do estoque do produto com um UPDATE e marcadores ?, e confirmar a mudança. O programa mostra o estoque no fim.
import sqlite3
con = sqlite3.connect("padaria.db")
with con:
con.execute("CREATE TABLE IF NOT EXISTS estoque (produto TEXT UNIQUE, quantidade INTEGER)")
con.executemany(
"INSERT OR IGNORE INTO estoque VALUES (?, ?)",
[("Pão francês", 80), ("Sonho", 12), ("Bolo de milho", 6)],
)
def vender(produto, quantidade):
# tire a quantidade vendida do estoque desse produto
pass
vender("Pão francês", 30)
vender("Sonho", 12)
for produto, quantidade in con.execute("SELECT produto, quantidade FROM estoque"):
print(f"{produto}: {quantidade}")
con.close()
import sqlite3
con = sqlite3.connect("padaria.db")
with con:
con.execute("CREATE TABLE IF NOT EXISTS estoque (produto TEXT UNIQUE, quantidade INTEGER)")
con.executemany(
"INSERT OR IGNORE INTO estoque VALUES (?, ?)",
[("Pão francês", 80), ("Sonho", 12), ("Bolo de milho", 6)],
)
def vender(produto, quantidade):
with con:
con.execute(
"UPDATE estoque SET quantidade = quantidade - ? WHERE produto = ?",
(quantidade, produto),
)
vender("Pão francês", 30)
vender("Sonho", 12)
for produto, quantidade in con.execute("SELECT produto, quantidade FROM estoque"):
print(f"{produto}: {quantidade}")
con.close()
O INSERT OR IGNORE grava os produtos só se ainda não existirem (o UNIQUE faria o INSERT comum dar erro na segunda vez que o programa roda no seu computador). Quer ir além? Faça a vender() recusar a venda quando não houver estoque suficiente. O Projeto: Estoque com SQLite monta um programa completo com essas peças.
Resumo
- O
sqlite3vem com o Python.sqlite3.connect("arquivo.db")abre o banco (e cria o arquivo se ele não existir, sem avisar). con.execute("SQL", valores)roda um comando;executemany()roda o mesmo comando para uma lista.- Valores entram sempre por marcadores:
?com uma tupla ((valor,), com a vírgula) ou:nomecom um dicionário. Nunca com f-string,+ou%: é a porta do SQL injection. fetchall()devolve uma lista de tuplas;fetchone(), uma tupla ouNone; o cursor também funciona numfor. Comsqlite3.Row, a linha aceita o nome da coluna.- Mudou alguma coisa?
commit(). Sem ele, os dados somem sem erro. Owith con:confirma se tudo der certo e desfaz tudo se der erro, mas não fecha a conexão. - Os erros vêm do módulo:
OperationalError(tabela inexistente, SQL errado),ProgrammingError(marcadores e valores não batem, conexão fechada),IntegrityError(regra da tabela, comoUNIQUE).