
Projeto SQLite

SQLite
SQLite é um mecanismo de banco de dados relacional de código aberto, escrito em C por D. Richard Hipp, em 2000. Ele não necessita da instalação de um servidor para o seu funcionamento, como ocorre com a maioria dos demais bancos de dados, acessando diretamente um arquivo em disco. O estado completo de uma base de dados fica armazenado nesse arquivo, geralmente com extensão arquivo.db
, .sqlite
ou .db3
. que pode ser utilizado diretamente em diversas plataformas. Ele não é um aplicativo independente e sim uma biblioteca que é incorporada junto com os aplicativos, sendo o mecanismo de banco de dados mais usado, servindo para armazenamento e manipulação de dados em navegadores da Web, sistemas operacionais, telefones celulares e outros sistemas integrados.

O SQLite usa uma sintaxe de SQL parecida com a do PostgreSQL, mas não impõe a verificação de tipo, tornando possível, por exemplo, se inserir uma string em uma coluna definida como inteiro. Como em outras versões de bancos de dados relacionais, o SQLite armazena dados em tabelas que podem conter campos de vários tipos de dados, como texto ou números inteiros. Essas tabelas podem ser acessadas (construídas, modificadas e consultadas) por meio de consultas SQL que realizam operações “CRUD” (criar, ler, atualizar, excluir). Um banco de dados SQLite pode ser criptografado usando o SQLite Encryption Extension (SEE) ou outra tecnologia, de forma a proteger dados de extrações não autorizadas.
Diversos Sistemas Gerenciadores de Bancos de Dados, SGBD, (em inglês RDBMS, Relational Database Management System) estão disponíveis para o SQLite, entre eles o SQLiteStudio, DB Browser, DBeaver. Também existem diversos plugins para navegadores e IDEs (como o VSCode).
SQLite no VSCode
O VSCode possui um plugin muito interessante para auxiliar no desenvolvimento com SQLite. Para usá-lo instale o plugin (extension) vscode-sqlite
. Os seguintes recursos ficam disponíveis:
- consulta a bancos de dados SQLite, visualização de tabelas, exportações de resultados para json, csv e html.
- uso da barra lateral (explorer) para listar bancos de dados, tabelas, colunas e views.
- preenchimento automático de palavras-chave, nomes de tabelas e colunas. Para isso deve-se vincular um banco de dados a um documento SQL, usando o comando: USE DATABASE.
- emissão de mensagens de erros amigáveis apontando o local do erro.
Existem comandos para criar novos arquivos sqlite, novas consultas, editar e executar scripts de consulta, visualização rápida de BD, fechar e removar um BD, atualizar, exibir resultados de consultas.
Para iniciar o uso crie um documento, por exemplo meuBD.db
. Clique nele (com botão direito) e gere um nova consulta. O arquivo é transformado automaticamente em um banco do SQLite. Também clicando com botão direito selecione “Open Database” para visualizar as tabelas e ter acesso a vários outros comandos. Consultas digitadas no editor podem ser executadas com as opções “Run Query” ou “Run Selected Query”.
Comandos SQLite
Existem diversas maneiras de inserir comandos SQL em um banco SQLite. Em um gerenciador de bancos de dados podemos abrir uma área de inserção de consultas e digitar, interativamente esses comandos. Alternativamente, se temos uma sequência de consultas válidas gravadas no arquivo consultas.sqljunto podemos executar no prompt de comando:
cat consultas.sql | sqlite3 test1.db
# ou
sqlite3 test2.db ".read consultas.sql"
# ou
sqlite3 test3.db < definicoes.sql
# no windows
sqlite3.exe test4.db ".read definicoes.sql"
Esses comandos produzem respectivamente os arquivos test_n.db após as execuções das consultas em definicoes.sql.
Projeto: vendas
Como uma ilustração de uso do SQLite vamos construir uma banco de dados para controle de uma loja, com tabelas para seus clientes, funcionários, fornecedores e itens vendidos. Todas as consultas SQL podem estar em um único arquivo .sql, mas nós as listaremos por partes para comentar os seus efeitos.
Consultas de definição das tabelas
O comando CREATE TABLE
serve para inserir uma nova tabela no banco de dados. IF NOT EXISTS
instrui a consulta a ser executada somente se a tabela ainda não foi criada. As definições de campo seguem dentro dos parênteses. O campo id INTEGER PRIMARY KEY AUTOINCREMENT
é um índice inteiro, usado como chave primária e de autoincremento. Campos definidos como NOT NULL não podem ser deixados nulos.
Primeiro criamos uma tabela no prompt de comando:
>> sqlite3 vendas.db
Em seguida criamos as tabelas. Para usar esse arquivo podemos usar os comandos listados acima ou abrir um gerenciador de bancos de dados e inserir as consultas nele. O uso do VSCode ou diretamente no código com o sqlite3 do python são exemplos desse uso.
-- criando a tabela clientes
CREATE TABLE IF NOT EXISTS clientes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nome VARCHAR(100) NOT NULL,
sobrenome TEXT NOT NULL,
email VARCHAR(100) NOT NULL,
cidade TEXT NOT NULL,
estado VARCHAR(2) NOT NULL,
cep INTEGER NOT NULL
);
-- criando a tabela de funcionarios
CREATE TABLE IF NOT EXISTS funcionarios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nome VARCHAR(100) NOT NULL,
sobrenome TEXT NOT NULL,
email TEXT NOT NULL,
senha VARCHAR(20) NOT NULL,
cargo VARCHAR(133),
endereco TEXT NOT NULL,
cidade VARCHAR(150) NOT NULL,
estado VARCHAR(2) NOT NULL,
cep INTEGER NOT NULL
);
-- Criando a tabela fornecedores
CREATE TABLE IF NOT EXISTS fornecedores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nome VARCHAR(100) NOT NULL,
cnpj VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
endereco TEXT NOT NULL,
cidade VARCHAR(150) NOT NULL,
estado VARCHAR(2) NOT NULL,
cep INTEGER NOT NULL
);
Após a execução desses consultas temos as tabelas clientes, funcionarios e fornecedores. Digamos que queremos alterar uma tabela para acrescentar, renomear ou excluir algum campo. ALTER TABLE
é a consulta usada.
-- para alterar uma tabela (alterando clientes)
ALTER TABLE clientes ADD data_aniversario DATE;
ALTER TABLE clientes ADD endereco TEXT NOT NULL;
-- para renomear um campo
ALTER TABLE clientes RENAME data_aniversario TO aniversario;
-- para excluir um campo
ALTER TABLE clientes DROP COLUMN aniversario;
Primeiro inserimos data_aniversario e endereco, depois renomeamos data_aniversario para aniversario, depois excluímos o campo aniversario. Da mesma forma tabelas inteiras podem ser excluídas com DROP TABLE
.
-- criar uma tabela para ser apagada depois
CREATE TABLE IF NOT EXISTS usuarios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nome VARCHAR(100) NOT NULL,
codigo INTEGER NOT NULL
);
-- excluir a tabela recém criada
DROP TABLE usuarios;
Operações de apagamento devem ser executadas com cuidado pois os dados não podem ser recuperados!
Observe que no modelo adotado acima os cargos dos funcionários são inseridos como textos que devem ser repetidos para diversos funcionários com o mesmo cargo. Outra possibilidade consiste em ter uma tabela com os cargos em separado, referenciados na tabela funcionarios por meio de um id. Vamos fazer essas alterações.
-- criar a tabela cargos
CREATE TABLE IF NOT EXISTS cargos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
descricao VARCHAR(200) NOT NULL
);
-- exclui a coluna cargo de funcionarios
ALTER TABLE funcionarios DROP COLUMN cargo;
-- insere cargo_id
ALTER TABLE funcionarios ADD COLUMN cargo_id INTEGER REFERENCES cargos(id);
O último comando falaria se não existisse a tabela referenciada cargos. O campo cargo_id é uma chave estrangeira (foreign key), ligado à tabela cargos, pelo seu campo id. Vamos aplicar o mesmo conceito na criação de chaves estrangeiras para produtos vendidos e vendas.
-- tabela produtos
CREATE TABLE IF NOT EXISTS produtos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
fornecedor_id INTEGER,
descricao VARCHAR(100),
preco DECIMAL(10,2),
FOREIGN KEY (fornecedor_id) REFERENCES fornecedores (id)
);
-- tabela vendas
CREATE TABLE IF NOT EXISTS vendas (
id INTEGER PRIMARY KEY AUTOINCREMENT,
cliente_id INTEGER NOT NULL,
funcionario_id INTEGER NOT NULL,
data_venda DATETIME NOT NULL,
total DECIMAL (10,2) NOT NULL,
descricao TEXT,
FOREIGN KEY (cliente_id) REFERENCES clientes (id),
FOREIGN KEY (funcionario_id) REFERENCES funcionarios (id)
);
-- tabela itens_vendas
CREATE TABLE IF NOT EXISTS itens_vendas (
id INTEGER PRIMARY KEY AUTOINCREMENT,
venda_id INTEGER NOT NULL,
produto_id INTEGER NOT NULL,
quantidade INTEGER NOT NULL,
subtotal DECIMAL (10,2) NOT NULL,
FOREIGN KEY (venda_id) REFERENCES vendas (id),
FOREIGN KEY (produto_id) REFERENCES produto (id)
);
Os relacionamentos entre as tabelas expressam o fato de que um funcionário pode fazer várias vendas, cada venda pode conter vários ítens de produtos, um único fornecedor pode ser responsável por vários produtos e mais de um funcionário podem ter o mesmo cargo.
Vemos que as, após todos esses passos, as tabelas possuem os seguintes relacionamentos:

Consultas de inserção e leitura de dados
Uma vez definidas as tabelas passamos a inserir dados. Faremos também consultas para verificar os dados inseridos. Dados são inseridos com INSERT INTO
. O nome da tabela e os campos são fornecidos e os valores a inserir. SELECT *
significa “selecione todos os campos”.
INSERT INTO clientes (nome, sobrenome, email, cidade, estado, cep, endereco)
VALUES
('Caio', 'Zuretta', 'cz@hotmail.com', 'Seattle', 'WA', 123456789,'23rd Street AWE');
SELECT * FROM clientes;
id nome sobrenome email cidade estado cep endereco
1 Caio Zuretta cz@hotmail.com Seattle WA 123456789 23rd Street AWE
-- inserindo outro cliente
INSERT INTO clientes (nome, sobrenome, email, endereco, cidade, estado, cep )
VALUES ('Polka', 'Brita', 'pbrita@gmail.com', 'Av. Contorno 432', 'Belo Horizonte', 'MG', 30876786);
SELECT id, nome, sobrenome FROM clientes;
id nome sobrenome
1 Caio Zuretta
2 Polka Brita
-- várias linhas podem ser inseridas na mesma consulta
INSERT INTO clientes (nome, sobrenome, email, endereco, cidade, estado, cep)
VALUES
('Antonio', 'Tony', 'tmatador@gigamail.com.br', 'R. Pedro II, 34', 'Rio de Janeiro', 'RJ', 21654897),
('Martha', 'Maertis', 'marthis@onlymail.com', 'R. Joinha, 654', 'Goiania', 'GO', 41546546),
('Orlando', 'Orlandis', 'orlas@gmail.com', 'Av, Só que Não, 34', 'Itabira', 'MG', 35654654),
('Mirtes', 'Mello', 'mellom@gmail.com', 'SQL 123', 'Brasília', 'DF', 145428214);
-- uma operação sobre todos as linhas de um campo UPDATE clientes
SET email = UPPER(email);
SELECT email FROM clientes WHERE nome="Mirtes";
email
MELLOM@GMAIL.COM
-- vamos retornar as minúsculas no email
UPDATE clientes SET email = LOWER(email);
SELECT email FROM clientes WHERE nome="Mirtes";
email
mellom@gmail.com
-- inserindo dados na tabela funcionarios
INSERT INTO funcionarios (nome, sobrenome, email, senha, cargo_id, endereco, cidade, estado, cep)
VALUES
('Pedro', 'Altusser', 'pedroalt@email.com', '123456', 1, 'R. João Paulo, 534', 'Rio de Janeiro', 'RJ', 21654897),
('Levindo', 'Lopes', 'lopest@gmail.com', '234456', 1, 'R. Paulo II, 534', 'Ardósias', 'RJ', 21115114),
('Silvana', 'Gomes', 'silvana@gmail.com', '344456', 2, 'R. Paulo I, 4', 'Ardósias', 'RJ', 21651145),
('Lucas', 'Sêtte', 'lucas@gmail.com', '3er456', 3, 'R. Bahia, 1355', 'Belo Horizonte', 'MG', 31454232);
SELECT nome, email, cidade, estado, cep, cargo_id FROM funcionarios WHERE estado = "MG";
nome email cidade estado cep cargo_id
Lucas lucas@gmail.com Belo Horizonte MG 31454232 3
-- inserindo cargos
INSERT INTO cargos (descricao) VALUES ('Gerente'), ('Vendedor'), ('Desenvolvedor');
SELECT * FROM cargos;
id descricao
1 Gerente
2 Vendedor
3 Desenvolvedor
-- alterar o valor de um campo já inserido
UPDATE funcionarios SET cargo_id=1 WHERE id=1;
-- agora a tabela funcionarios está no estado
SELECT * FROM funcionarios;
id nome sobrenome email senha endereco cidade estado cep cargo_id
1 Pedro Altusser pedroalt@email.com 123456 R. João Paulo, 534 Rio de Janeiro RJ 21654897 3
2 Levindo Lopes lopest@gmail.com 234456 R. Paulo II, 534 Ardósias RJ 21115114 1
3 Silvana Gomes silvana@gmail.com 344456 R. Paulo I, 4 Ardósias RJ 21651145 2
4 Lucas Sêtte lucas@gmail.com 3er456 R. Bahia, 1355 Belo Horizonte MG 31454232 3

Uma vez preenchidas as tabelas podemos fazer consultas de todos os tipos. Para ler dados da tabela funcionarios com a descrição dos cargos em cargos usamos INNER JOIN
. As duas consultas abaixo são equivalentes:
-- INNER JOIN
SELECT f.nome, c.descricao FROM funcionarios f
INNER JOIN cargos c WHERE f.cargo_id = c.id;
SELECT f.nome, c.descricao FROM funcionarios f
INNER JOIN cargos c ON (f.cargo_id = c.id);
nome descricao
Pedro Desenvolvedor
Levindo Gerente
Silvana Vendedor
Lucas Desenvolvedor
-- aliases podem ser dados para qualquer campo. Strings são concatenados com ||
SELECT nome || " " || sobrenome as 'Funcionário' FROM funcionarios;
Funcionário
Pedro Altusser
Levindo Lopes
Silvana Gomes
Lucas Sêtte
Aliases foram usados acima para atribuir nomes às tabelas (como em FROM funcionarios f INNER JOIN cargos c
) ou a compos resultados da consultas (como em nome || " " || sobrenome as 'Funcionário'
).
Consultas podem ser modificadas pelas condições em WHERE
, e partes dos campos podem ser encontrados com LIKE
. %
representa qualquer grupo de caracteres, _
(underline) significa um caracter.
-- Uma consulta simples com dupla condição
SELECT id, nome || " " || sobrenome as 'Funcionário', estado
FROM clientes WHERE estado = "MG" and id=2;
id Funcionário estado
2 Polka Brita MG
-- para apagar um ou mais registros (o registro listado acima)
DELETE FROM clientes WHERE estado = "MG" and id=2;
-- nome iniciado com "Ma" e a letra "a" no sobrenome
SELECT id, nome, sobrenome FROM clientes WHERE nome LIKE 'Ma%' AND sobrenome LIKE '%a%';
id nome sobrenome
4 Martha Maertis
SELECT id, nome, sobrenome FROM clientes WHERE nome LIKE '_a%';
id nome sobrenome
1 Caio Zuretta
4 Martha Maertis
SELECT id, nome, sobrenome FROM clientes WHERE nome LIKE '_a___a';
id nome sobrenome
4 Martha Maertis
Para fazer outras consultas cruzadas, em mais de uma tabela, vamos entrar dados nas tabelas fornecedores e produtos.
-- inserindo fornecedores e produtos
INSERT INTO fornecedores (nome, cnpj, email, endereco, cidade, estado, cep)
VALUES
('Microsoft', '234.456-098', 'ms@ms.com', 'R. Pedro Alves, 34', 'Sorocaba', 'SP', 1234567),
('Apple', '212.1226-128', 'apps@apps.com', 'R. Gerino Silva, 456', 'Brasília', 'DF', 61256767),
('Lenovo', '2456.1567-676', 'lenovo@lenovo.com', 'R. Power Guido, 786', 'Manaus', 'AM', 23452345),
('Dell', '222.453-444', 'del@del.com', 'R. Vaga Errante, 13', 'Sorocaba', 'SP', 1234567),
('Logitec', '666.7777-888', 'logi@log.com', 'R. Ulva Gods Silva, 90', 'Brasília', 'DF', 61256767),
('Multilaser', '1111.9999-888', 'miltila@multi.com', 'R. Volvo Zona, 76', 'Itabira', 'MG', 3114045);
INSERT INTO produtos (fornecedor_id, descricao, preco)
VALUES
(2, 'iPAD', 12345.80),
(1, 'Windows 11', 67.90),
(5, 'Teclado sem fio', 99.00),
(3, 'Notebook Intel', 1560.00),
(15, 'Mouse Chines', 13.33),
(16, 'Chingling Roteador', 59.89);
SELECT * FROM fornecedores;
SELECT * FROM produtos;
-- as tabelas resultado estão nas imagens abaixo

Com essas definições de valores vamos fazer algumas consultas para exibir a sintaxe de consultas JOIN
. JOIN
e INNER JOIN
são idênticos.
SELECT p.id, f.nome, p.descricao, p.preco FROM produtos p
JOIN fornecedores f ON (p.fornecedor_id = f.id);
id nome descricao preco
1 Apple iPAD 12345.8
2 Microsoft Windows 11 67.9
3 Logitec Teclado sem fio 99
4 Lenovo Notebook Intel 1560
SELECT p.id 'COD.', f.nome 'Vendedor', p.descricao 'Produto' , p.preco 'Preço'
FROM produtos p RIGHT JOIN fornecedores f ON (p.fornecedor_id = f.id);
COD. Vendedor Produto Preço
1 Apple iPAD 12345.8
2 Microsoft Windows 11 67.9
3 Logitec Teclado sem fio 99
4 Lenovo Notebook Intel 1560
NULL Dell NULL NULL
NULL Multilaser NULL NULL
Suponha que desejamos fazer um relatório com todas as vendas para o cliente de sobrenome “Arbinger”. Podemos primeiro encontrar o id do cliente e, daí, todas as vendas para ele. Fazemos um JOIN para encontrar o nome dos funcionários que fizeram as vendas.
-- o id do cliente é
SELECT id FROM clientes WHERE sobrenome="Arbinger";
3
-- as vendas desse cliente
SELECT * FROM vendas
WHERE cliente_id = (SELECT id FROM clientes WHERE sobrenome="Arbinger");
-- as vendas associadas ao funcionário vendedor
SELECT v.data_venda, v.total, v.descricao, f.nome, f.sobrenome FROM vendas v
JOIN funcionarios f
WHERE f.id = v.funcionario_id
and v.cliente_id = (SELECT id FROM clientes WHERE sobrenome="Arbinger");
data_venda total descricao nome sobrenome
10/12/2020 200 Filial 1 Levindo Lopes
11/12/2020 100 Filial 1 Levindo Lopes
13/12/2020 280 Filial 2 Pedro Altusser
17/12/2020 290 Filial 4 Levindo Lopes
Se, além disso quisermos saber quais os itens foram vendidos fazemos:
SELECT v.data_venda, v.total, v.descricao, f.nome, f.sobrenome, p.descricao as "Produto"
FROM vendas v
JOIN funcionarios f
JOIN itens_vendas i
JOIN produtos p
WHERE f.id = v.funcionario_id and v.id = i.venda_id and i.produto_id = p.id
and v.cliente_id = (SELECT id FROM clientes WHERE sobrenome="Arbinger");
data_venda total descricao nome sobrenome Produto
10/12/2020 200 Filial 1 Levindo Lopes Windows 11
10/12/2020 200 Filial 1 Levindo Lopes Teclado sem fio
11/12/2020 100 Filial 1 Levindo Lopes iPAD
Observe que dois itens foram listados relativos à venda do dia 10/12/2020 e um item para o dia 11/12. Nenhum item foi listado para as vendas dos dias 13 e 17/12.
sqlite3 e Python
O python traz um módulo instalado com a biblioteca padrão para integrar o SQLite com o código. Para usá-lo basta importar esse módulo chamado sqlite3.
import sqlite3
connection = sqlite3.connect("escola.db")
cursor = connection.cursor()
sql = """
CREATE TABLE IF NOT EXISTS alunos (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
nome TEXT,
idade INTEGER
);
"""
cursor.execute(sql)
sql = """
INSERT INTO alunos (nome, idade) VALUES
('Alice', 21),
('Letícia', 22),
('Vinicius', 23),
('Guilherme', 12),
('Marcos', 37),
('Pedro', 6),
('Wanda', 20),
('Aluísio', 10);
"""
cursor.execute(sql)
connection.commit()
dados = cursor.execute("SELECT * FROM alunos WHERE idade <=' 22")
for linha in dados:
print(linha[0], linha[1], linha[2])
1 Alice 21
4 Guilherme 12
6 Pedro 6
7 Wanda 20
8 Aluísio 10
Com o comando connection = sqlite3.connect("escola.db")
o banco de dados é criado, se já não existe. Um cursor é um objeto usado para fazer a relação entre o código (e as queries) com o banco. O objeto dados é um iterável que retorna tuplas com os resultados da query.
Digamos que queremos fazer uma consulta ao banco de dados pre-existente phylos.db
, usado nos exercícios anteriores. Para isso estabelecemos uma nova conecção com esse banco de dados.
connection = sqlite3.connect("vendas.db")
sql = """
SELECT v.data_venda, v.total, v.descricao, f.nome, f.sobrenome, p.descricao as "Produto"
FROM vendas v
JOIN funcionarios f
JOIN itens_vendas i
JOIN produtos p
WHERE f.id = v.funcionario_id and v.id = i.venda_id and i.produto_id = p.id
and v.cliente_id = (SELECT id FROM clientes WHERE sobrenome="Arbinger");
"""
cursor = connection.cursor()
data = cursor.execute(sql)
for row in data:
print(row)
# o resultado é:
('10/12/2020', 200, 'Filial 1', 'Levindo', 'Lopes', 'Windows 11')
('10/12/2020', 200, 'Filial 1', 'Levindo', 'Lopes', 'Teclado sem fio')
('11/12/2020', 100, 'Filial 1', 'Levindo', 'Lopes', 'iPAD')
sqlite3 e pandas
Uma outra possibilidade interessante é a de integrar os dataframes do pandas com o SQLite. Para isso importamos o sqlite3
e o pandas
e estabelecemos uma conexão com o banco de dados. Um dataframe pode ser carregado diretamente com o resultado da consulta com pandas.read_sql(sql, connection)
.
import sqlite3
import pandas as pd
connection = sqlite3.connect("vendas.db")
sql = """
SELECT v.data_venda, v.total, v.descricao, f.nome, f.sobrenome
FROM vendas v JOIN funcionarios f
WHERE f.id = v.funcionario_id;
"""
cursor = connection.cursor()
# apenas para ver o resultado da consulta fazemos:
data = cursor.execute(sql)
for row in data:
print(row)
# o resultado:
('10/12/2020', 200, 'Filial 1', 'Levindo', 'Lopes')
('11/12/2020', 100, 'Filial 1', 'Levindo', 'Lopes')
('12/12/2020', 120, 'Filial 2', 'Levindo', 'Lopes')
('13/12/2020', 280, 'Filial 2', 'Pedro', 'Altusser')
('17/12/2020', 290, 'Filial 4', 'Levindo', 'Lopes')
df = pd.read_sql(sql, connection)
print(df)
# o resultado:
data_venda total descricao nome sobrenome
0 10/12/2020 200 Filial 1 Levindo Lopes
1 11/12/2020 100 Filial 1 Levindo Lopes
2 12/12/2020 120 Filial 2 Levindo Lopes
3 13/12/2020 280 Filial 2 Pedro Altusser
4 17/12/2020 290 Filial 4 Levindo Lopes
df.to_sql("tabela_2", connection)
O último comando insere uma tabela tabela_2 no banco de dados vendas.db com os campos e valores desse dataframe.
Bibliografia
Sobre SQLite
Sobre o SQLite3, no Python