Programador Leigo
SQLite 10 min leitura 15 MAR 2026

SQLite com Python: banco de dados sem instalar nada

Crie e manipule bancos de dados locais com SQLite e o módulo sqlite3 que já vem com Python.


O que é o SQLite?

O SQLite é um banco de dados relacional que funciona dentro de um único arquivo. Diferente do PostgreSQL ou MySQL, ele não precisa de um servidor rodando — o banco inteiro fica em um arquivo .db no seu computador. O Python já traz o módulo sqlite3 na biblioteca padrão, então basta importar e usar.

Quando usar (e quando não usar)

  • Use para protótipos, apps desktop/mobile, testes automatizados e projetos pessoais.
  • Não use para aplicações web com muitos acessos simultâneos, sistemas com alta disponibilidade ou bancos muito grandes (acima de alguns GB).

Nesses casos, migre para PostgreSQL ou MySQL. A boa notícia é que o SQL é praticamente o mesmo.

Conectando ao banco

import sqlite3

conexao = sqlite3.connect("tarefas.db")
cursor = conexao.cursor()

Se o arquivo não existir, o SQLite cria automaticamente. O cursor é o objeto que executa comandos SQL. Para criar um banco em memória (útil para testes), use sqlite3.connect(":memory:").

Criando tabelas

cursor.execute("""
    CREATE TABLE IF NOT EXISTS tarefas (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        titulo TEXT NOT NULL,
        descricao TEXT,
        prioridade TEXT DEFAULT 'media',
        concluida INTEGER DEFAULT 0,
        criada_em TEXT DEFAULT CURRENT_TIMESTAMP
    )
""")

conexao.commit()

O IF NOT EXISTS evita erros caso a tabela já exista. O commit() salva as alterações — sem ele, nada é persistido.

Tipo Descrição Exemplo
INTEGER Números inteiros 1, 42, -7
REAL Números decimais 3.14, 99.90
TEXT Texto (strings) "Python", "Ola"
BLOB Dados binários Imagens, arquivos
NULL Valor ausente None

INSERT: inserindo dados

cursor.execute(
    "INSERT INTO tarefas (titulo, descricao, prioridade) VALUES (?, ?, ?)",
    ("Estudar Python", "Completar o capitulo sobre SQLite", "alta")
)
conexao.commit()

# Inserir varias de uma vez
tarefas = [
    ("Comprar cafe", None, "baixa"),
    ("Revisar codigo", "Pull request do projeto X", "alta"),
    ("Responder emails", None, "media"),
]

cursor.executemany(
    "INSERT INTO tarefas (titulo, descricao, prioridade) VALUES (?, ?, ?)",
    tarefas
)
conexao.commit()

NUNCA faça isso

Concatenar strings em queries é uma falha de segurança grave chamada SQL injection:

# ERRADO - vulneravel a SQL injection!
titulo = "Estudar Python"
cursor.execute(f"INSERT INTO tarefas (titulo) VALUES ('{titulo}')")

Um usuário malicioso poderia enviar '); DROP TABLE tarefas; -- como título e destruir seu banco. Sempre use placeholders (?).

SELECT: consultando dados

# Todos os registros
cursor.execute("SELECT id, titulo, prioridade FROM tarefas")
for tarefa in cursor.fetchall():
    print(f"[{tarefa[0]}] {tarefa[1]} (prioridade: {tarefa[2]})")

# Filtrar com WHERE
cursor.execute("SELECT titulo FROM tarefas WHERE prioridade = ?", ("alta",))

# Busca parcial com LIKE
cursor.execute("SELECT titulo FROM tarefas WHERE titulo LIKE ?", ("%Python%",))

# Buscar um unico registro
cursor.execute("SELECT * FROM tarefas WHERE id = ?", (1,))
tarefa = cursor.fetchone()
if tarefa:
    print(f"Encontrada: {tarefa[1]}")

Para retornar dicionários em vez de tuplas, configure o row_factory:

conexao.row_factory = sqlite3.Row
cursor = conexao.cursor()

cursor.execute("SELECT * FROM tarefas WHERE prioridade = ?", ("alta",))
for tarefa in cursor.fetchall():
    print(f"{tarefa['titulo']} - {tarefa['prioridade']}")

Ordenar e limitar

cursor.execute("SELECT titulo FROM tarefas ORDER BY criada_em DESC LIMIT 3")

# Paginacao: pular 3, pegar as proximas 3
cursor.execute("SELECT titulo FROM tarefas LIMIT 3 OFFSET 3")

UPDATE: atualizando dados

cursor.execute(
    "UPDATE tarefas SET concluida = 1 WHERE id = ?",
    (1,)
)
conexao.commit()
print(f"{cursor.rowcount} tarefa(s) atualizada(s)")

DELETE: removendo dados

cursor.execute("DELETE FROM tarefas WHERE id = ?", (5,))
conexao.commit()

# Remover todas as concluidas
cursor.execute("DELETE FROM tarefas WHERE concluida = 1")
conexao.commit()

Cuidado: DELETE FROM tarefas sem WHERE apaga tudo. Sempre use filtros.

Context managers: segurança automática

Use o with para garantir que tudo seja salvo e fechado corretamente:

import sqlite3

with sqlite3.connect("tarefas.db") as conexao:
    cursor = conexao.cursor()
    cursor.execute(
        "INSERT INTO tarefas (titulo, prioridade) VALUES (?, ?)",
        ("Nova tarefa", "media")
    )
    # commit automatico ao sair do bloco sem erros
    # rollback automatico se houver excecao

Projeto prático: agenda de contatos

Vamos construir uma agenda no terminal com todas as operações CRUD:

import sqlite3


def criar_tabela(cursor):
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS contatos (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nome TEXT NOT NULL,
            telefone TEXT,
            email TEXT UNIQUE
        )
    """)


def adicionar(cursor):
    nome = input("Nome: ")
    telefone = input("Telefone: ")
    email = input("Email: ")
    try:
        cursor.execute(
            "INSERT INTO contatos (nome, telefone, email) VALUES (?, ?, ?)",
            (nome, telefone, email)
        )
        print(f"Contato '{nome}' adicionado!")
    except sqlite3.IntegrityError:
        print("Erro: ja existe um contato com esse email.")


def listar(cursor):
    cursor.execute("SELECT id, nome, telefone, email FROM contatos ORDER BY nome")
    contatos = cursor.fetchall()
    if not contatos:
        print("Nenhum contato cadastrado.")
        return
    print(f"\n{'ID':<5} {'Nome':<20} {'Telefone':<15} {'Email':<25}")
    print("-" * 65)
    for c in contatos:
        print(f"{c[0]:<5} {c[1]:<20} {c[2] or '-':<15} {c[3] or '-':<25}")


def buscar(cursor):
    termo = input("Buscar por nome: ")
    cursor.execute(
        "SELECT id, nome, telefone, email FROM contatos WHERE nome LIKE ?",
        (f"%{termo}%",)
    )
    for c in cursor.fetchall():
        print(f"[{c[0]}] {c[1]} | {c[2] or '-'} | {c[3] or '-'}")


def remover(cursor):
    id_contato = input("ID do contato para remover: ")
    cursor.execute("DELETE FROM contatos WHERE id = ?", (id_contato,))
    print("Removido." if cursor.rowcount > 0 else "Nao encontrado.")


def main():
    with sqlite3.connect("agenda.db") as conexao:
        cursor = conexao.cursor()
        criar_tabela(cursor)

        while True:
            print("\n=== Agenda de Contatos ===")
            print("1. Adicionar  2. Listar  3. Buscar  4. Remover  0. Sair")
            opcao = input("Opcao: ")

            acoes = {"1": adicionar, "2": listar, "3": buscar, "4": remover}
            if opcao == "0":
                print("Ate logo!")
                break
            elif opcao in acoes:
                acoes[opcao](cursor)
            else:
                print("Opcao invalida.")


if __name__ == "__main__":
    main()

SQLite vs bancos "de verdade"

Característica SQLite PostgreSQL / MySQL
Instalação Nenhuma (embutido) Servidor separado
Concorrência Uma escrita por vez Múltiplas escritas
Rede Apenas local Acesso remoto
Tamanho Ideal até poucos GB Terabytes sem problema
Usuários Um por vez (geralmente) Milhares simultâneos

A regra prática: comece com SQLite para desenvolver e testar. Quando for para produção com múltiplos usuários, migre para PostgreSQL. Como o SQL é o mesmo, a migração costuma ser simples.

Próximos passos

Com o SQLite você já consegue criar sistemas completos de armazenamento local. O próximo passo natural é aprender SQL com mais profundidade (JOINs, agregações, subconsultas) e depois explorar ORMs como o SQLAlchemy, que permitem trabalhar com bancos de dados usando classes Python em vez de SQL puro.

Continue lendo

Compartilhar