SQLite é um dos sistemas de gerenciamento de bases de dados relacionais (RDBMS) mais populares. É leve, o que significa que não ocupa muito espaço no seu sistema. Uma de suas melhores características é que é servidor-livre, portanto você não precisa instalar ou gerenciar um servidor separado para usá-lo.
Em vez disso, ele armazena tudo em um simples arquivo no seu computador. Também não exige nenhuma configuração, portanto não há nenhum processo de configuração complicado, fazendo dele perfeito para iniciantes e pequenos projetos.
SQLite é uma ótima escolha para aplicações pequenas a médias porque é fácil de usar, rápido e consegue realizar a maioria das tarefas que bases de dados maiores conseguem, mas sem a necessidade de gerenciar software extra. Se você está construindo um projeto pessoal ou prototipando uma nova aplicação, SQLite é uma opção sólida para iniciar rapidamente.
Neste tutorial, você vai aprender a trabalhar com SQLite usando Python. Aqui está o que vamos abordar neste tutorial:
Este tutorial é perfeito para quem quer começar com bases de dados sem mergulhar em configurações complexas.
Como configurar seu ambiente Python
Antes de trabalhar com SQLite, vamos garantir que seu ambiente Python está pronto. Aqui está como configurar tudo.
Instalando o Python
Se você ainda não tiver o Python instalado no seu sistema, você pode baixá-lo do site oficial do Python. Siga com as instruções de instalação para o seu sistema operacional (Windows, macOS ou Linux).
Para verificar se o Python está instalado, abra seu terminal (ou prompt de comando) e digite:
python --version
Isso deve mostrar a versão atual do Python instalada. Se não estiver instalada, siga com as instruções no site do Python.
Instalando o módulo SQLite3
A boa notícia é que SQLite3 vem built-in com Python! Você não precisa instalá-lo separadamente, pois está incluído na biblioteca padrão do Python. Isso significa que você pode começar a usá-lo mesmo assim sem nenhuma configuração adicional.
Como Criar um Ambiente Virtual (Opcional mas Recomendado)
É uma boa ideia criar um ambiente virtual para cada projeto para manter suas dependências organizadas. Um ambiente virtual é como um tabuleiro limpo onde você pode instalar pacotes sem afetar sua instalação global do Python.
Para criar um ambiente virtual, siga estes passos:
-
Primeiro, abra sua terminal ou prompt de comando e navegue até o diretório onde você quer criar seu projeto.
-
Execute o seguinte comando para criar um ambiente virtual:
python -m venv env
Aqui, env
é o nome do ambiente virtual. Você pode atribuí-lo a qualquer coisa que você preferir.
- Ative o ambiente virtual:
# Use o comando para Windows
env\Scripts\activate
# Use o comando para macOS/Linux:
env/bin/activate
Após ativar o ambiente virtual, você notará que o prompt de sua terminal mudou, mostrando o nome do ambiente virtual. Isto significa que você agora está trabalhando dentro dele.
Instalando Bibliotecas Necessárias
Vamos precisar de algumas bibliotecas adicionais para esse projeto. Especificamente, vamos usar:
-
pandas
: Esta é uma biblioteca opcional para manipular e exibir dados em formato de tabela, útil para casos de uso avançados. -
faker
: Esta biblioteca ajudará-nos a gerar dados falsos, como nomes e endereços aleatórios, que podemos inserir em nossa base de dados para fins de teste.
Para instalar pandas
e faker
, basta executar os seguintes comandos:
pip install pandas faker
Isso instala ambos pandas
e faker
na sua ambiente virtual. Com isso, sua ambiente está pronto e você está pronto para começar a criar e gerenciar sua base de dados SQLite em Python!
Como Criar uma Base de Dados SQLite
Uma base de dados é uma maneira estruturada de armazenar e gerenciar dados de modo a que sejam facilmente acessados, atualizados e organizados. É como um sistema de arquivos digital que permite armazenar grandes quantidades de dados de forma eficiente, quer para uma aplicação simples quer para um sistema mais complexo. As bases de dados usam tabelas para organizar dados, com linhas e colunas representando registros individuais e seus atributos.
Como as bases de dados SQLite funcionam
Diferentemente de outros sistemas de bases de dados, o SQLite é um banco de dados sem servidor. Isto significa que não é necessário configurar ou gerenciar um servidor, tornando-o leve e fácil de usar. Todos os dados são armazenados em um único arquivo no seu computador, que você pode mover, compartilhar ou fazer backup facilmente. Apesar de sua simplicidade, o SQLite é o suficiente poderoso para lidar com muitas tarefas de banco de dados comuns e é amplamente usado em aplicativos móveis, sistemas embarcados e projetos de pequeno a médio porte.
Como Criar um Novo Banco de Dados SQLite
Vamos criar um novo banco de dados SQLite e aprender a interagir com ele usando a biblioteca sqlite3
do Python.
Conectando ao Banco de Dados
Já que o sqlite3
está pré-instalado, você precisa apenas importá-lo em seu script Python. Para criar um novo banco de dados ou conectar a um existente, usamos o método sqlite3.connect()
. Este método pega o nome do arquivo do banco de dados como um argumento. Se o arquivo não existir, o SQLite criará automaticamente.
import sqlite3
# Conectar ao banco de dados SQLite (ou criá-lo se não existir)
connection = sqlite3.connect('my_database.db')
Neste exemplo, um arquivo chamado my_database.db
é criado no mesmo diretório onde está o script. Se o arquivo já existir, o SQLite abrirá apenas a conexão com ele.
Criando um Cursor
Uma vez que você tem uma conexão, o próximo passo é criar um objeto cursor. O cursor é responsável por executar comandos e consultas de SQL no banco de dados.
# Criar um objeto cursor
cursor = connection.cursor()
Fechando a Conexão
Depois de terminar de trabalhar com o banco de dados, é importante fechar a conexão para liberar quaisquer recursos. Você pode fechar a conexão com o seguinte comando:
# Fechar a conexão do banco de dados
connection.close()
No entanto, você deve fechar a conexão apenas depois de terminar todas suas operações.
Quando você executar seu script Python, um arquivo chamado my_database.db
será criado na pasta de trabalho atual. Você agora criou com sucesso seu primeiro banco de dados SQLite!
Como Usar o Gerenciador de Contexto para Abrir e Fechar Conexões
O Python fornece uma maneira mais eficiente e mais limpa de manipular conexões de banco de dados usando a instrução with
, também conhecida como gerenciadora de contexto. A instrução with
abre e fecha automaticamente a conexão, garantindo que a conexão seja fechada corretamente mesmo se um erro ocorrer durante as operações de banco de dados. Isso elimina a necessidade de chamar manualmente connection.close()
.
Aqui está como você pode usar a instrução with
para manipular conexões de banco de dados:
import sqlite3
# Passo 1: Use 'with' para se conectar ao banco de dados (ou criar um) e fechar automaticamente quando terminar
with sqlite3.connect('my_database.db') as connection:
# Passo 2: Crie um objeto cursor para interagir com o banco de dados
cursor = connection.cursor()
print("Database created and connected successfully!")
# Não é necessário chamar connection.close(); é feito automaticamente!
A partir de agora, nossos exemplos de código futuros usarão a instrução with
para gerenciar conexões com bancos de dados de forma eficiente. Isto tornará o código mais conciso e fácil de manter.
Como Criar Tabelas de Banco de Dados
Agora que criamos um banco de dados SQLite e conectamos a ele, o próximo passo é criar tabelas dentro do banco de dados. Uma tabela é onde armazenaremos nossos dados, organizados em linhas (registros) e colunas (atributos). Neste exemplo, criaremos uma tabela chamada Students
para armazenar informações sobre estudantes, que reutilizaremos nas seções seguintes.
Para criar uma tabela, usamos a instrução SQL CREATE TABLE
. Este comando define a estrutura da tabela, incluindo os nomes das colunas e os tipos de dados para cada coluna.
Aqui está um simples comando SQL para criar uma tabela Students
com os seguintes campos:
-
id
: Um identificador único para cada estudante (um inteiro). -
name: O nome do estudante (texto).
-
age: A idade do estudante (um inteiro).
-
email: O endereço de email do estudante (texto).
O comando SQL para criar esta tabela teria o seguinte aspecto:
CREATE TABLE Students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER,
email TEXT
);
Nós podemos executar este comando SQL CREATE TABLE
em Python usando a biblioteca sqlite3
. Vamos ver como fazer isso.
import sqlite3
# Use 'with' para se conectar à base de dados SQLite e fechar automaticamente a conexão quando terminar
with sqlite3.connect('my_database.db') as connection:
# Crie um objeto cursor
cursor = connection.cursor()
# Escreva o comando SQL para criar a tabela de Alunos
create_table_query = '''
CREATE TABLE IF NOT EXISTS Students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER,
email TEXT
);
'''
# Execute o comando SQL
cursor.execute(create_table_query)
# Confirme as mudanças
connection.commit()
# Exiba uma mensagem de confirmação
print("Table 'Students' created successfully!")
-
IF NOT EXISTS
: Isso garante que a tabela só será criada se ela não existir, evitando erros se a tabela tiver sido criada anteriormente. -
connection.commit()
: Isso salva (confirma) as mudanças na base de dados.
Quando você executar o código Python acima, ele criará a tabela Alunos
no arquivo de banco de dados my_database.db
. Você também verá uma mensagem no terminal confirmando que a tabela foi criada com sucesso.
Se você estiver usando o Visual Studio Code, você pode instalar a extensão SQLite Viewer para visualizar bancos de dados SQLite.
Tipos de Dados no SQLite e Seu Mapeamento para Python
SQLite suporta vários tipos de dados, os quais precisamos compreender ao definir nossas tabelas. Aqui está uma visão geral rápida dos tipos de dados comuns no SQLite e como eles se correspondem com tipos em Python:
Tipo de Dado SQLite | Descrição | Equivalente em Python |
INTEGER | Números inteiros | int |
TEXT | String de texto | str |
REAL | Números de ponto flutuante | float |
BLOB | Dados binários (por exemplo, imagens, arquivos) | bytes |
NULL | Representa nenhum valor ou dados ausentes | None |
Em nossa tabela Students
:
-
id
é do tipoINTEGER
, que corresponde aoint
do Python. -
name
eemail
são do tipoTEXT
, que correspondem aostr
do Python. -
idade
também é do tipoINTEGER
, mapeado para o Pythonint
.
Como Inserir Dados em uma Tabela
Agora que nossa tabela Alunos
foi criada, é hora de começar a inserir dados no banco de dados. Nessa seção, vamos ver como inserir tanto registros individuais quanto múltiplos usando Python e SQLite, e como evitar problemas de segurança comuns como o Injeção de SQL ao usar consultas parametrizadas.
Como Inserir um Registro Único
Para inserir dados no banco de dados, usamos o comando SQL INSERT INTO
. Vamos começar inserindo um registro único na nossa tabela Alunos
.
Aqui está a sintaxe básica de inserção de um registro:
INSERT INTO Students (name, age, email)
VALUES ('John Doe', 20, '[email protected]');
No entanto, em vez de escrever SQL diretamente no nosso script Python com valores codificados, usaremos consultas parametrizadas para tornar o nosso código mais seguro e flexível. As consultas parametrizadas ajudam a prevenir a Injeção de SQL, um ataque comum em que usuários maliciosos podem manipular a consulta SQL passando entradas prejudiciais.
Aqui é como podemos inserir um registro único na tabela Alunos
usando uma consulta parametrizada:
import sqlite3
# Use 'with' para abrir e fechar a conexão automaticamente
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Inserir um registro na tabela Students
insert_query = '''
INSERT INTO Students (name, age, email)
VALUES (?, ?, ?);
'''
student_data = ('Jane Doe', 23, '[email protected]')
cursor.execute(insert_query, student_data)
# Comitante as mudanças automaticamente
connection.commit()
# Não é necessário chamar connection.close(); é feito automaticamente!
print("Record inserted successfully!")
Os marcadores de posição ?
representam os valores a serem inseridos na tabela. Os valores reais são passados como um tuplo (student_data
) no método cursor.execute()
.
Como Inserir Múltiplos Registros
Se você quiser inserir múltiplos registros de uma só vez, você pode usar o método executemany()
em Python. Este método pega uma lista de tuplas, onde cada tupla representa um registro.
Para tornar nosso exemplo mais dinâmico, podemos usar a biblioteca Faker
para gerar dados de estudante aleatórios. Isso é útil para testes e simulando cenários reais.
from faker import Faker
import sqlite3
# Inicializar Faker
fake = Faker(['en_IN'])
# Use 'with' para abrir e fechar a conexão automaticamente
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Inserir um registro na tabela Students
insert_query = '''
INSERT INTO Students (name, age, email)
VALUES (?, ?, ?);
'''
students_data = [(fake.name(), fake.random_int(
min=18, max=25), fake.email()) for _ in range(5)]
# Executar a consulta para múltiplos registros
cursor.executemany(insert_query, students_data)
# Comitante as mudanças
connection.commit()
# Exibir mensagem de confirmação
print("Fake student records inserted successfully!")
Neste código:
-
O
Faker()
gera nomes aleatórios, idades e emails para estudantes. A passagem da localidade ([‘en_IN’]
) é opcional. -
cursor.executemany()
: Este método permite que inseramos vários registros de uma só vez, tornando o código mais eficiente. -
students_data
: Uma lista de tuplas onde cada tupla representa os dados de um estudante.
Como Tratar com Problemas Comuns: Injeção SQL
A injeção SQL é uma vulnerabilidade de segurança onde atacantes podem inserir ou manipular consultas SQL fornecendo entradas prejudiciais. Por exemplo, um atacante pode tentar injetar código como '; DROP TABLE Students; --
para deletar a tabela.
Ao usarmos consultas parametrizadas (como mostrado acima), evitamos este problema. Os marcadores de posição ?
nas consultas parametrizadas garantem que os valores de entrada são tratados como dados, e não como parte da instrução SQL. Isto torna impossível a execução de código malicioso.
Como Consultar Dados
Agora que inserimos algum dado na nossa tabela Students
, vamos aprender como recuperar dados da tabela. Vamos explorar diferentes métodos para buscar dados em Python, incluindo fetchone()
, fetchall()
, e fetchmany()
.
Para consultar dados de uma tabela, usamos a instrução SELECT
. Aqui está um comando SQL simples para selecionar todas as colunas da tabela Students
:
SELECT * FROM Students;
Este comando recupera todos os registros e colunas da tabela Students
. Podemos executar essa consulta SELECT
em Python e buscar os resultados.
Como Recuperar Todos os Registros
Veja como podemos recuperar todos os registros da tabela Students
:
import sqlite3
# Use 'with' para se conectar à base de dados SQLite
with sqlite3.connect('my_database.db') as connection:
# Crie um objeto cursor
cursor = connection.cursor()
# Escreva o comando SQL para selecionar todos os registros da tabela Students
select_query = "SELECT * FROM Students;"
# Execute o comando SQL
cursor.execute(select_query)
# Busque todos os registros
all_students = cursor.fetchall()
# Exiba resultados no terminal
print("All Students:")
for student in all_students:
print(student)
Neste exemplo, o método fetchall()
recupera todas as linhas retornadas pela consulta como uma lista de tuplas.
All Students:
(1, 'Jane Doe', 23, '[email protected]')
(2, 'Bahadurjit Sabharwal', 18, '[email protected]')
(3, 'Zayyan Arya', 20, '[email protected]')
(4, 'Hemani Shukla', 18, '[email protected]')
(5, 'Warda Kara', 20, '[email protected]')
(6, 'Mitali Nazareth', 19, '[email protected]')
Como Recuperar um Registro Único
Se você quiser recuperar apenas um registro, você pode usar o método fetchone()
:
import sqlite3
# Use 'with' para conectar à base de dados SQLite
with sqlite3.connect('my_database.db') as connection:
# Crie um objeto cursor
cursor = connection.cursor()
# Escreva o comando SQL para selecionar todos os registros da tabela Students
select_query = "SELECT * FROM Students;"
# Execute o comando SQL
cursor.execute(select_query)
# Busque um registro
student = cursor.fetchone()
# Mostre o resultado
print("First Student:")
print(student)
Output:
First Student:
(1, 'Jane Doe', 23, '[email protected]')
Como Buscar Múltiplos Registros
Para buscar um número específico de registros, você pode usar fetchmany(size)
:
import sqlite3
# Use 'with' para conectar à base de dados SQLite
with sqlite3.connect('my_database.db') as connection:
# Crie um objeto cursor
cursor = connection.cursor()
# Escreva o comando SQL para selecionar todos os registros da tabela Students
select_query = "SELECT * FROM Students;"
# Execute o comando SQL
cursor.execute(select_query)
# Busque três registros
three_students = cursor.fetchmany(3)
# Mostrar resultados
print("Three Students:")
for student in three_students:
print(student)
Output:
Three Students:
(1, 'Jane Doe', 23, '[email protected]')
(2, 'Bahadurjit Sabharwal', 18, '[email protected]')
(3, 'Zayyan Arya', 20, '[email protected]')
Como Usar pandas
para uma Melhor Apresentação de Dados
Para uma melhor apresentação de dados, podemos usar a biblioteca pandas
para criar um DataFrame
a partir dos nossos resultados de consulta. Isso facilita a manipulação e visualização dos dados.
Aqui está como buscar todos os registros e exibi-los como um DataFrame pandas:
import sqlite3
import pandas as pd
# Use 'with' to connect to the SQLite database
with sqlite3.connect('my_database.db') as connection:
# Write the SQL command to select all records from the Students table
select_query = "SELECT * FROM Students;"
# Use pandas to read SQL query directly into a DataFrame
df = pd.read_sql_query(select_query, connection)
# Display the DataFrame
print("All Students as DataFrame:")
print(df)
Output:
All Students as DataFrame:
id name age email
0 1 Jane Doe 23 [email protected]
1 2 Bahadurjit Sabharwal 18 [email protected]
2 3 Zayyan Arya 20 [email protected]
3 4 Hemani Shukla 18 [email protected]
4 5 Warda Kara 20 [email protected]
5 6 Mitali Nazareth 19 [email protected]
A função pd.read_sql_query()
executa a consulta SQL e retorna diretamente os resultados como um DataFrame do pandas.
Como Atualizar e Excluir Dados
Nesta seção, vamos aprender a atualizar registros existentes e excluir registros da nossa tabela Students
usando comandos SQL em Python. Isso é essencial para gerenciar e manter seus dados efetivamente.
Atualizar Registros Existentes
Para modificar registros existentes em um banco de dados, usamos o comando SQL UPDATE
. Este comando permite que você altere os valores de colunas específicas em uma ou mais linhas com base em uma condição especificada.
Por exemplo, se quisermos atualizar a idade de um aluno, o comando SQL teria este aspecto:
UPDATE Students
SET age = 21
WHERE name = 'Jane Doe';
Agora, vamos escrever código Python para atualizar a idade de um aluno específico na nossa tabela Students
.
import sqlite3
# Utilize 'with' para se conectar à base de dados SQLite
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Comando SQL para atualizar a idade de um aluno
update_query = '''
UPDATE Students
SET age = ?
WHERE name = ?;
'''
# Dados para a atualização
new_age = 21
student_name = 'Jane Doe'
# Executar o comando SQL com os dados
cursor.execute(update_query, (new_age, student_name))
# Confirmar as mudanças para salvar a atualização
connection.commit()
# Exibir uma mensagem de confirmação
print(f"Updated age for {student_name} to {new_age}.")
Neste exemplo, utilizámos consultas parametrizadas para prevenir o注入 de SQL.
Como Excluir Registros da Tabela
Para remover registros de um banco de dados, usamos o comando SQL DELETE
. Este comando permite que removamos uma ou mais linhas com base em uma condição especificada.
Por exemplo, se quisermos excluir um aluno chamado ‘Jane Doe’, o comando SQL teria este aspecto:
DELETE FROM Students
WHERE name = 'Jane Doe';
Vamos escrever um código Python para excluir um aluno específico da nossa tabela Students
usando o statement with
.
import sqlite3
# Utilize 'with' para se conectar à base de dados SQLite
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Comando SQL para excluir um aluno
delete_query = '''
DELETE FROM Students
WHERE name = ?;
'''
# Nome do aluno a ser excluído
student_name = 'Jane Doe'
# Executar o comando SQL com os dados
cursor.execute(delete_query, (student_name,))
# Confirmar as mudanças para salvar a exclusão
connection.commit()
# Exibir uma mensagem de confirmação
print(f"Deleted student record for {student_name}.")
Considerações Importantes
-
Condições: Sempre use a cláusula
WHERE
ao atualizar ou excluir registros para evitar modificar ou remover todas as linhas na tabela. Sem a cláusulaWHERE
, o comando afeta todas as linhas na tabela. -
Backup: É uma boa prática fazer backup de seu banco de dados antes de realizar atualizações ou exclusões, especialmente em ambientes de produção.
Como Usar Transações
Uma transação é uma seqüência de uma ou mais operações SQL que são tratadas como uma única unidade de trabalho. No contexto de um banco de dados, uma transação permite que você execute várias operações que todas sejam bem-sucedidas ou nenhuma delas. Isso garante que seu banco de dados permaneça em um estado consistente, mesmo na presença de erros ou problemas inesperados.
Por exemplo, se você está transferindo dinheiro entre dois contas bancárias, você queira que ambas as operações de débito de uma conta e o crédito para a outra sejam bem-sucedidas ou falharem juntas. Se uma operação falha, a outra não deve ser executada para manter a consistência.
Por que usar transações?
-
Atomicity: As transações garantem que uma série de operações é tratada como uma unidade única. Se uma operação falhar, nenhuma das operações será aplicada ao banco de dados.
-
Consistency: As transações auxiliam a manter a integridade do banco de dados, garantindo que todas as regras e constraintes sejam seguidas.
-
Isolation: Cada transação opera independentemente das outras, prevenindo interferências não intencionadas.
-
Durability: Uma vez que uma transação é confirmada, as mudanças são permanentes, mesmo com o falha do sistema.
Quando usar Transações?
Você deve usar transações quando:
-
Realizar múltiplas operações relacionadas que devem ser bem-sucedidas ou falharem juntas.
-
Modificar dados críticos que requerem consistência e integridade.
-
Trabalhando com operações que podem falhar, como transações financeiras ou migrações de dados.
Como Gerenciar Transações em Python
No SQLite, as transações são gerenciadas usando os comandos BEGIN
, COMMIT
, e ROLLBACK
. No entanto, quando usando o módulo sqlite3
em Python, você gerencia as transações através do objeto de conexão.
Iniciando uma Transação
Uma transação começa implícitamente quando você executa qualquer instrução SQL. Para iniciar uma transação explicitamente, você pode usar o comando BEGIN
:
cursor.execute("BEGIN;")
No entanto, geralmente é desnecessário iniciar uma transação manualmente, pois o SQLite inicia uma transação automaticamente quando você executa uma instrução SQL.
Como Comitar uma Transação
Para salvar todas as mudanças feitas durante uma transação, você usa o método commit()
. Isso torna todas as modificações permanentes no banco de dados.
connection.commit()
Já usamos o método commit()
nos exemplos fornecidos acima.
Rolling Back a Transação
Se algo der errado e você quiser reverter as mudanças feitas durante uma transação, você pode usar o método rollback()
. Isso desfaz todas as mudanças feitas desde o início da transação.
connection.rollback()
Exemplo de Uso de Transações em Python
Para ilustrar o uso de transações em um cenário real do mundo, vamos criar uma nova tabela chamada Clientes
para gerenciar as contas de clientes. Neste exemplo, assumiremos que cada cliente tem um saldo
. Vamos adicionar dois clientes a esta tabela e executar uma operação de transferência de fundos entre eles.
Primeiro, vamos criar a tabela Clientes
e inserir dois clientes:
import sqlite3
# Criar a tabela Clientes e adicionar dois clientes
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Criar tabela Clientes
create_customers_table = '''
CREATE TABLE IF NOT EXISTS Customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
balance REAL NOT NULL
);
'''
cursor.execute(create_customers_table)
# Inserir dois clientes
cursor.execute(
"INSERT INTO Customers (name, balance) VALUES (?, ?);", ('Ashutosh', 100.0))
cursor.execute(
"INSERT INTO Customers (name, balance) VALUES (?, ?);", ('Krishna', 50.0))
connection.commit()
Agora, vamos executar a operação de transferência de fundos entre Ashutosh e Krishna:
import sqlite3
def transfer_funds(from_customer, to_customer, amount):
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
try:
# Iniciar uma transação
cursor.execute("BEGIN;")
# Subtrair quantia do remetente
cursor.execute(
"UPDATE Customers SET balance = balance - ? WHERE name = ?;", (amount, from_customer))
# Adicionar quantia ao destinatário
cursor.execute(
"UPDATE Customers SET balance = balance + ? WHERE name = ?;", (amount, to_customer))
# Comitear as mudanças
connection.commit()
print(
f"Transferred {amount} from {from_customer} to {to_customer}.")
except Exception as e:
# Se ocorrer um erro, desfazer a transação
connection.rollback()
print(f"Transaction failed: {e}")
# Exemplo de uso
transfer_funds('Ashutosh', 'Krishna', 80.0)
Neste exemplo, primeiro criamos uma tabela Customers
e inserimos dois clientes, Ashutosh com um saldo de ₹100, e Krishna com um saldo de ₹50. Depois, realizamos um transferência de ₹80 de Ashutosh para Krishna. Utilizando transações, garantimos que ambas as debêntures de Ashutosh e a crédito de Krishna forem executadas como uma única operação atômica, mantendo a integridade dos dados em caso de quaisquer erros. Se a transferência falhar (por exemplo, devido a saldo insuficiente), a transação será revertida, deixando ambas as contas inalteradas.
Como Optimizar o Desempenho de Consultas SQLite com Indexação
A indexação é uma técnica poderosa usada em bancos de dados para melhorar o desempenho de consultas. Um índice, essencialmente, é uma estrutura de dados que armazena a localização das linhas com base em valores de colunas específicas, semelhante à indexação no final de um livro que ajuda você a localizar rapidamente um tópico.
Sem um índice, o SQLite precisa scanner toda a tabela linha por linha para encontrar os dados relevantes, o que torna ineficiente conforme o conjunto de dados cresce. Utilizando um índice, o SQLite pode pular diretamente para as linhas necessárias, melhorando significativamente a execução das consultas.
Como Preencher o Banco de Dados com Dados Falsos
Para testar eficazmente o impacto da indexação, precisamos de um conjunto de dados grande. Em vez de adicionar registros manualmente, podemos usar a biblioteca faker
para gerar dados falsos rapidamente. Nessa seção, vamos gerar 10.000 registros falsos e inserir eles na nossa tabela Students
. Isto simulará um cenário real em que os bancos de dados crescem e o desempenho das consultas se torna importante.
Vamos usar o método executemany()
para inserir os registros conforme abaixo:
import sqlite3
from faker import Faker
# Inicializar a biblioteca Faker
fake = Faker(['en_IN'])
def insert_fake_students(num_records):
"""Generate and insert fake student data into the Students table."""
fake_data = [(fake.name(), fake.random_int(min=18, max=25),
fake.email()) for _ in range(num_records)]
# Usar 'with' para manipular a conexão com o banco de dados
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Inserir dados falsos na tabela Students
cursor.executemany('''
INSERT INTO Students (name, age, email)
VALUES (?, ?, ?);
''', fake_data)
connection.commit()
print(f"{num_records} fake student records inserted successfully.")
# Inserir 10.000 registros falsos na tabela Students
insert_fake_students(10000)
Ao executar este script, 10.000 registros de estudantes falsos serão adicionados à tabela Students
. Na próxima seção, nós consultaremos o banco de dados e compararemos o desempenho das consultas com e sem índices.
Como Consultar Sem Índices
Nesta seção, nós consultaremos a tabela Students
sem nenhum índice para observar como o SQLite age quando não há nenhuma otimização em vigor. Isto servirá como uma linha de base para comparar o desempenho quando nós adicionamos índices depois.
Sem índices, o SQLite realiza uma scanner de tabela inteira, o que significa que ele deve verificar todas as linhas da tabela para encontrar resultados correspondentes. Para pequenos conjuntos de dados, isso é gerenciável, mas conforme o número de registros cresce, o tempo para a busca aumenta dramaticamente. Vamos ver isso em ação executando uma consulta básica de SELECT
para procurar por um estudante específico por nome e medir quanto tempo leva para executar.
Primeiro, nós consultaremos a tabela Students
procurando por um estudante com um nome específico. Nós vamos registrar o tempo de execução da consulta usando o módulo time
do Python para medição do desempenho.
import sqlite3
import time
def query_without_index(search_name):
"""Query the Students table by name without an index and measure the time taken."""
# Conectar com a base de dados usando 'with'
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Medir a hora de início
start_time = time.perf_counter_ns()
# Executar uma consulta SELECT para encontrar um aluno por nome
cursor.execute('''
SELECT * FROM Students WHERE name = ?;
''', (search_name,))
# Recuperar todos os resultados (deveriam existir apenas um ou alguns em prática)
results = cursor.fetchall()
# Medir a hora de fim
end_time = time.perf_counter_ns()
# Calcular o tempo total gasto
elapsed_time = (end_time - start_time) / 1000
# Exibir os resultados e o tempo gasto
print(f"Query completed in {elapsed_time:.5f} microseconds.")
print("Results:", results)
# Exemplo: Pesquisar um aluno por nome
query_without_index('Ojasvi Dhawan')
Aqui está a saída:
Query completed in 1578.10000 microseconds.
Results: [(104, 'Ojasvi Dhawan', 21, '[email protected]')]
Ao executar o script acima, verá quanto tempo leva para pesquisar na tabela Students
sem nenhuma indexação. Por exemplo, se a tabela tiver 10.000 registros, a consulta poderá levar de 1000 a 2000 microsegundos, dependendo do tamanho da tabela e do hardware. Isto pode não parecer muito lento para um pequeno conjunto de dados, mas a performance degrada conforme mais registros são adicionados.
Nós usamos time.perf_counter_ns()
para medir o tempo de execução da consulta em nanosegundos. Este método é altamente preciso para a análise de pequenos intervalos de tempo. Convertemos o tempo para microsegundos (us
) para melhor leitura.
Apresentando o Plano de Consulta
Ao trabalhar com bancos de dados, entender como as consultas são executadas pode ajudar a identificar pontos de bottleneck de desempenho e a otimizar seu código. O SQLite fornece uma ferramenta útil para isso chamada EXPLAIN QUERY PLAN
, que permite analisar as etapas que o SQLite toma para recuperar dados.
Nesta seção, nós vamos apresentar como usar EXPLAIN QUERY PLAN
para visualizar e entender o funcionamento interno de uma consulta – especificamente, como o SQLite realiza um scan de tabela completo quando não há índices.
Vamos usar EXPLAIN QUERY PLAN
para ver como o SQLite recupera dados da tabela Students
sem nenhum índice. Vamos procurar um aluno por nome, e o plano de consulta revelará as etapas que o SQLite toma para encontrar as linhas correspondentes.
import sqlite3
def explain_query(search_name):
"""Explain the query execution plan for a SELECT query without an index."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Use EXPLAIN QUERY PLAN para analisar como a consulta é executada
cursor.execute('''
EXPLAIN QUERY PLAN
SELECT * FROM Students WHERE name = ?;
''', (search_name,))
# Recupera e exibe o plano de consulta
query_plan = cursor.fetchall()
print("Query Plan:")
for step in query_plan:
print(step)
# Exemplo: Análise do plano de consulta para a busca por nome
explain_query('Ojasvi Dhawan')
Quando você executar este código, o SQLite retornará uma análise de como planeja executar a consulta. Aqui está um exemplo de como a saída pode parecer:
Query Plan:
(2, 0, 0, 'SCAN Students')
Isso indica que o SQLite está fazendo um scan de tabela inteiro (full table scan) para encontrar as linhas onde a coluna name
corresponde ao valor fornecido (Ojasvi Dhawan
). since there is no index on the name
column, SQLite must examine each row in the table.
Como Criar um Índice
Criar um índice em uma coluna permite que o SQLite encontre linhas mais rápido durante operações de consulta. Em vez de scanner toda a tabela, o SQLite pode usar o índice para pular diretamente para as linhas relevantes, acelerando significativamente as consultas – especialmente aquelas envolvendo grandes conjuntos de dados.
Para criar um índice, use o seguinte comando SQL:
CREATE INDEX IF NOT EXISTS index-name ON table (column(s));
Neste exemplo, vamos criar um índice na coluna name
da tabela Students
. Veja como você pode fazer isso usando o Python:
import sqlite3
import time
def create_index():
"""Create an index on the name column of the Students table."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Comando SQL para criar um índice na coluna name
create_index_query = '''
CREATE INDEX IF NOT EXISTS idx_name ON Students (name);
'''
# Medir o tempo de início
start_time = time.perf_counter_ns()
# Executar o comando SQL para criar o índice
cursor.execute(create_index_query)
# Medir o tempo de início
end_time = time.perf_counter_ns()
# Comitar as mudanças
connection.commit()
print("Index on 'name' column created successfully!")
# Calcular o tempo total gasto
elapsed_time = (end_time - start_time) / 1000
# Exibir os resultados e o tempo gasto
print(f"Query completed in {elapsed_time:.5f} microseconds.")
# Chamar a função para criar o índice
create_index()
Output:
Index on 'name' column created successfully!
Query completed in 102768.60000 microseconds.
Ainda que a criação do índice leve este tempo (102768,6 microssegundos), é uma operação única. Você ainda obterá uma aceleração substancial quando executar várias consultas. Nas seções seguintes, nós consultaremos novamente o banco de dados para observar as melhorias de desempenho obtidas com este índice.
Como Consultar com Índices
Nesta seção, performaremos a mesma consulta SELECT
que executamos anteriormente, mas desta vez aproveitaremos o índice que criamos na coluna name
da tabela Students
. Mediremos e registraremos o tempo de execução para observar as melhorias de desempenho fornecidas pelo índice.
import sqlite3
import time
def query_with_index(student_name):
"""Query the Students table using an index on the name column."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Comando SQL para selecionar um aluno por nome
select_query = 'SELECT * FROM Students WHERE name = ?;'
# Medir o tempo de execução
start_time = time.perf_counter_ns() # Iniciar o cronômetro
# Executar a consulta com o nome do aluno fornecido
cursor.execute(select_query, (student_name,))
result = cursor.fetchall() # Recuperar todos os resultados
end_time = time.perf_counter_ns() # Encerrar o cronômetro
# Calcular o tempo decorrido em microsegundos
execution_time = (end_time - start_time) / 1000
# Exibir resultados e tempo de execução
print(f"Query result: {result}")
print(f"Execution time with index: {execution_time:.5f} microseconds")
# Exemplo: Pesquisar um aluno por nome
query_with_index('Ojasvi Dhawan')
Eis o que obtemos na saída:
Query result: [(104, 'Ojasvi Dhawan', 21, '[email protected]')]
Execution time with index: 390.70000 microseconds
Podemos observar uma redução significativa no tempo de execução em comparação com a execução da consulta sem o índice.
Vamos analisar o plano de execução da consulta para a consulta com o índice na coluna name
da tabela Students
. Se você executar o mesmo script novamente para explicar a consulta, você obterá a saída abaixo:
Query Plan:
(3, 0, 0, 'SEARCH Students USING INDEX idx_name (name=?)')
O plano agora mostra que a consulta usa o índice idx_name
, reduzindo significativamente o número de linhas que precisam ser扫描, o que resulta em execução de consulta mais rápida.
Comparando Resultados de Performance
Agora, vamos resumir os resultados de performance obtidos quando consultando com e sem índices.
Comparação de Tempo de Execução
Tipo de Consulta | Tempo de Execução (microsegundos) |
Sem Índice | 1578,1 |
Com Índice | 390,7 |
Resumo da Melhoria de Performance
-
A consulta com o índice é aproximadamente 4,04 vezes mais rápida que a consulta sem o índice.
-
O tempo de execução melhorou em aproximadamente 75,24% após a adição do índice.
Práticas Recomendadas para Usar Índices
Índices podem melhorar significativamente a performance do seu banco de dados SQLite, mas devem ser usados com sabedoria. Aqui estão algumas práticas recomendadas para considerar quando trabalhando com índices:
Quando e por Que Usar Índices
-
Colunas de Consulta Frequentes: Use índices em colunas que são frequentemente usadas em consultas
SELECT
, especialmente aquelas usadas em cláusulasWHERE
,JOIN
eORDER BY
. Isto é porque a indexação destas colunas pode reduzir significativamente o tempo de execução das consultas. -
Constraints de Unicidade: Quando você tem colunas que devem manter valores únicos (como nomes de usuário ou endereços de e-mail), criar um índice pode enforcar eficientemente este constrangimento.
-
Conjuntos de Dados grandes: Para tabelas com um grande número de registros, os índices se tornam cada vez mais benéficos. Eles permitem consultas rápidas, o que é essencial para manter o desempenho conforme seu dado cresce.
-
Índices compostos: Considere criar índices compostos para consultas que filtram ou classificam por várias colunas. Por exemplo, se você frequentemente procura por alunos por ambos
nome
eidade
, um índice em ambas as colunas pode otimizar tais consultas.
Potenciais desvantagens dos índices
Ao mesmo tempo que os índices oferecem vantagens significativas, existem algumas potenciais desvantagens:
-
Operações de inserção/atualização mais lentas: Quando você insere ou atualiza registros em uma tabela com índices, o SQLite também deve atualizar o índice, o que pode abrandar essas operações. Isso ocorre porque cada inserção ou atualização exige sobrecarga adicional para manter a estrutura do índice.
-
Requerimentos de armazenamento aumentados: Os índices consomem espaço de disco adicional. Para tabelas grandes, o custo de armazenamento pode ser substancial. Considere isso ao projetar sua esquema de banco de dados, especialmente para sistemas com recursos de armazenamento limitados.
-
Gestão de Índices Complexos: Ter muitos índices pode complicar a gestão de bases de dados. Pode levar a situações onde há índices redundantes, o que pode degringolar o desempenho em vez de melhorá-lo. Revisionar regularmente e optimizar seus índices é uma boa prática.
Índices são ferramentas poderosas para otimizar consultas de banco de dados, mas exigem consideração cuidadosa. Encontrar o equilíbrio entre o melhor desempenho de leitura e o potencial sobrecarga nas operações de gravação é chave. Aqui estão algumas estratégias para alcançar esse equilíbrio:
-
Monitorar o Desempenho de Consultas: Use o
EXPLAIN QUERY PLAN
do SQLite para analisar como suas consultas funcionam com e sem índices. Isto pode ajudar a identificar quais índices são benéficos e quais podem ser desnecessários. -
Manutenção Regular: Revise regularmente seus índices e avalie se eles ainda são necessários. Remova índices redundantes ou raramente usados para simplificar as operações de sua base de dados.
-
Testar e Avaliar: Antes de implementar índices em um ambiente de produção, execute testes abrangentes para entender o impacto deles nas operações de leitura e gravação.
Ao seguir essas melhores práticas, você pode aproveitar os benefícios da indexação enquanto minimiza os potenciais desvantagens, melhorando assim a performance e eficiência da sua base de dados SQLite.
Como Tratar Erros e Exceções
Nesta seção, vamos discutir como tratar erros e exceções ao trabalhar com SQLite em Python. A correta manutenção de erros é crucial para manter a integridade de sua base de dados e garantir que seu aplicativo se comporta de forma preditiva.
Erros Comuns em Operações SQLite
Ao interagir com uma base de dados SQLite, pode ocorrer vários erros comuns:
-
Violações de Constraint: Este erro ocorre quando você tenta inserir ou atualizar dados que violam um constraint de banco de dados, como a unicidade do primary key ou constraint de foreign key. Por exemplo, tentar inserir uma chave primária duplicada disparará um erro.
-
Conflitos de Tipo de Dado: Tentar inserir dados de tipo errado (por exemplo, inserir uma string onde um número é esperado) pode resultar em um erro.
-
Erros de Banco de Dados travado: Se um banco de dados está sendo escrito por outro processo ou conexão, tentar acessá-lo pode resultar em um erro de “banco de dados travado”.
-
Erros de Sintaxe: Erros em sua sintaxe SQL resultarão em erros quando você tentar executar seus comandos.
Como Usar a Exception Handling do Python
As mecanismos de tratamento de exceções integrado do Python (try
e except
) são essenciais para gerenciar erros nas operações SQLite. Utilizando essas estruturas, você pode capturar exceções e responder adequadamente sem quebrar seu programa.
Aqui está um exemplo básico de como tratar erros ao inserir dados no banco de dados:
import sqlite3
def add_customer_with_error_handling(name, balance):
"""Add a new customer with error handling."""
try:
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
cursor.execute(
"INSERT INTO Customers (name, balance) VALUES (?, ?);", (name, balance))
connection.commit()
print(f"Added customer: {name} with balance: {balance}")
except sqlite3.IntegrityError as e:
print(f"Error: Integrity constraint violated - {e}")
except sqlite3.OperationalError as e:
print(f"Error: Operational issue - {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# Exemplo de uso
add_customer_with_error_handling('Vishakha', 100.0) # Válido
add_customer_with_error_handling('Vishakha', 150.0) # Entrada duplicada
Neste exemplo:
-
Capturamos
IntegrityError
, que é levantado para violações como restrições de unicidade. -
Capturamos
OperationalError
para problemas relacionados ao banco de dados gerais (como erros de banco de dados bloqueado). -
Também temos um bloco
except
genérico para lidar com quaisquer exceções inesperadas.
Saída:
Added customer: Vishakha with balance: 100.0
Error: Integrity constraint violated - UNIQUE constraint failed: Customers.name
Práticas de melhorias para garantir a integridade do banco de dados
-
Usar Transações: Sempre use transações (como discutido na seção anterior) quando realizando várias operações relacionadas. Isto ajuda a garantir que todas as operações sejam bem-sucedidas ou nenhuma, mantendo assim a consistência.
-
Validar Dados de Entrada: Antes de executar comandos SQL, valide os dados de entrada para garantir que eles atendam aos critérios esperados (por exemplo, tipos corretos, dentro de intervalos permitidos).
-
Capturar Exceções Específicas: Sempre capture exceções específicas para lidar com diferentes tipos de erros apropriadamente. Isto permite uma tratamento de erros mais claro e melhora o debug.
-
Registrar Erros: Em vez de apenas imprimir erros na console, considere registrar-los em um arquivo ou sistema de monitoramento. Isto ajudará você a rastrear problemas na produção.
-
Degradação graciosa: Projete seu aplicativo para lidar com erros graciosamente. Se uma operação falhar, forneça um feedback significativo ao utilizador em vez de bloquear a aplicação.
-
Fazer backup regular dos dados: Efectue regularmente cópias de segurança da sua base de dados para evitar a perda de dados em caso de falhas críticas ou corrupção.
-
Utilizar declarações preparadas: As declarações preparadas ajudam a evitar ataques de injeção de SQL e também podem fornecer melhor desempenho para consultas repetidas.
Como Exportar e Importar Dados [Seção Bônus]
Nesta seção, aprenderemos como exportar dados de um banco de dados SQLite para formatos comuns como CSV e JSON, bem como importar dados para o SQLite a partir desses formatos usando Python. Isso é útil para compartilhamento de dados, backup e integração com outros aplicativos.
Exportando dados do SQLite para CSV
Exportar dados para um arquivo CSV (Comma-Separated Values) é simples com as bibliotecas integradas do Python. Os ficheiros CSV são amplamente utilizados para armazenamento e troca de dados, tornando-os um formato conveniente para exportar dados.
Veja como exportar dados de uma tabela SQLite para um arquivo CSV:
import sqlite3
import csv
def export_to_csv(file_name):
"""Export data from the Customers table to a CSV file."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Executar uma consulta para obter todos os dados do cliente
cursor.execute("SELECT * FROM Customers;")
customers = cursor.fetchall()
# Escrever dados para CSV
with open(file_name, 'w', newline='') as csv_file:
csv_writer = csv.writer(csv_file)
csv_writer.writerow(['ID', 'Name', 'Balance']) # Escrevendo cabeçalho
csv_writer.writerows(customers) # Escrevendo linhas de dados
print(f"Data exported successfully to {file_name}.")
# Exemplo de uso
export_to_csv('customers.csv')
Como Exportar Dados para JSON
Do mesmo modo, você pode exportar dados the um arquivo JSON (Notação de Objeto JavaScript), que é um formato popular para intercâmbio de dados, especialmente em aplicações web.
Aqui está um exemplo de como exportar dados para JSON:
import json
import sqlite3
def export_to_json(file_name):
"""Export data from the Customers table to a JSON file."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
# Executar uma consulta para obter todos os dados do cliente
cursor.execute("SELECT * FROM Customers;")
customers = cursor.fetchall()
# Converta dados em uma lista de dicionários
customers_list = [{'ID': customer[0], 'Name': customer[1],
'Balance': customer[2]} for customer in customers]
# Escrever dados para JSON
with open(file_name, 'w') as json_file:
json.dump(customers_list, json_file, indent=4)
print(f"Data exported successfully to {file_name}.")
# Exemplo de uso
export_to_json('customers.json')
Como Importar Dados para SQLite de CSV
Você também pode importar dados de um arquivo CSV para uma base de dados SQLite. Isso é útil para preencher sua base de dados com conjuntos de dados existentes.
Aqui está como importar dados the um arquivo CSV:
import csv
import sqlite3
def import_from_csv(file_name):
"""Import data from a CSV file into the Customers table."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
Abrir o arquivo CSV para leitura
with open(file_name, 'r') as csv_file:
csv_reader = csv.reader(csv_file)
next(csv_reader) Pular a linha de cabeçalho
Inserir cada linha na tabela Customers
for row in csv_reader:
cursor.execute(
"INSERT INTO Customers (name, balance) VALUES (?, ?);", (row[1], row[2]))
connection.commit()
print(f"Data imported successfully from {file_name}.")
Exemplo de uso
import_from_csv('customer_data.csv')
Como importar dados para o SQLite a partir de JSON
De forma similar, importar dados de um arquivo JSON é simples. Você pode ler o arquivo JSON e inserir os dados na sua tabela SQLite.
Veja como fazer:
import json
import sqlite3
def import_from_json(file_name):
"""Import data from a JSON file into the Customers table."""
with sqlite3.connect('my_database.db') as connection:
cursor = connection.cursor()
Abrir o arquivo JSON para leitura
with open(file_name, 'r') as json_file:
customers_list = json.load(json_file)
Inserir cada cliente na tabela Customers
for customer in customers_list:
cursor.execute("INSERT INTO Customers (name, balance) VALUES (?, ?);", (customer['Name'], customer['Balance']))
connection.commit()
print(f"Data imported successfully from {file_name}.")
Exemplo de uso
import_from_json('customer_data.json')
Encerrando
E ai é só acabar! Este guia apresentou-lhe os fundamentos de trabalhar com o SQLite em Python, abrangendo tudo desde a configuração do seu ambiente até as consultas e manipulações de dados, bem como a exportação e importação de informações. Espero que tenha encontrado útil e que tenha despertado seu interesse em usar o SQLite para seus projetos.
Agora é hora de colocar seu conhecimento recente em prática! Encorajamo-lo a criar seu projeto usando o SQLite e o Python. Quer seja uma aplicação simples para gerenciar sua biblioteca, uma ferramenta de orçamento ou algo único, as possibilidades são infinitas.
Uma vez que você complete seu projeto, compartilhe-o no Twitter e marque-me! Gostaria de ver o que você criou e comemorar seus feitos.
Toda o código deste tutorial pode ser encontrado no GitHub. Obrigado por acompanhar, e pronto para programar!
Crie uma Tabela de Conteúdos para seus artigos do freeCodeCamp de graça usando a ferramenta TOC Generator.
Source:
https://www.freecodecamp.org/news/work-with-sqlite-in-python-handbook/