O Banco da Loja Aurora
Todas as aulas deste guia usam o mesmo banco de dados: o da Loja Aurora, uma loja de departamentos fictícia com sede em Teresina, no Piauí, que vende de tudo um pouco: papelaria, eletrônicos, utensílios de cozinha, livros, brinquedos, artigos de esporte, alimentos e coisas de jardim. Ela tem clientes em várias cidades, uma pequena equipe e quase três anos de pedidos registrados. Antes de começar a escrever consultas, vale conhecer a casa: quais tabelas existem, o que cada uma guarda e como elas se ligam. É o que esta aula faz, tabela por tabela.
- As 7 tabelas da Loja Aurora e o que cada uma guarda.
- As colunas principais de cada tabela, e os nomes exatos que você vai usar nas consultas.
- Como as tabelas se ligam pelos ids: o mapa do banco.
- Como seguir um pedido de ponta a ponta: quem comprou, quem atendeu, o que foi comprado e quanto custou.
- Que o banco tem casos especiais de propósito (dados que faltam, clientes que nunca compraram…), e em que aulas eles aparecem.
- Os primeiros tropeços com este banco: coluna na tabela errada, data no formato brasileiro e vírgula no lugar do ponto.
Os dados são inventados (nomes, emails, telefones, tudo fictício) e fixos: são os mesmos para todo mundo, sempre. No editor do guia, cada Rodar começa do banco limpo; no seu computador, é o loja.db que você criou em Instalar o SQLite (montado pelo aurora.sql ou baixado pronto como aurora.db: dá o mesmo arquivo). Por isso, todo resultado das aulas é o que você vai ver também.
A ideia: os cadernos da loja
Imagine a loja antes do computador. A dona tinha um caderno para cada assunto, e cada caderno anotava só o seu:
- o caderno dos departamentos (papelaria, eletrônicos…);
- o caderno dos fornecedores, as empresas que vendem para a loja;
- o caderno do estoque, um produto por linha, com preço e quantidade;
- o caderno dos clientes;
- o caderno dos funcionários;
- o talão de pedidos, um por venda;
- e, em cada folha do talão, as linhas do pedido: o que foi levado, quantas unidades, a que preço.
Cada caderno virou uma tabela. E quando um caderno precisa falar de outro (o pedido precisa dizer quem é o cliente), ele não copia o nome: anota o número da ficha do cliente. É o id que você conheceu em O que é um Banco de Dados.
O mapa
fornecedores (6) categorias (8)
▲ ▲
│ fornecedor_id categoria_id │
└──────── produtos (45) ──────┘
▲
│ produto_id
itens_pedido (220)
│ pedido_id
▼
clientes (30) ◄─── pedidos (90) ───► funcionarios (8) ◄─┐
cliente_id funcionario_id │ │
└────────┘
chefe_id
Leia cada seta como "aponta para": um produto aponta para a sua categoria e o seu fornecedor; um pedido aponta para o cliente que comprou e para o funcionário que atendeu; cada item de pedido aponta para o pedido de que faz parte e para o produto vendido; e cada funcionário aponta para o seu chefe, que é outro funcionário. Os números entre parênteses são as linhas de cada tabela.
SELECT 'categorias', COUNT(*) FROM categorias UNION ALL SELECT 'fornecedores', COUNT(*) FROM fornecedores UNION ALL SELECT 'produtos', COUNT(*) FROM produtos UNION ALL SELECT 'clientes', COUNT(*) FROM clientes UNION ALL SELECT 'funcionarios', COUNT(*) FROM funcionarios UNION ALL SELECT 'pedidos', COUNT(*) FROM pedidos UNION ALL SELECT 'itens_pedido', COUNT(*) FROM itens_pedido;
Essa consulta contou as linhas das sete tabelas e empilhou as respostas. Ela usa coisas que você só vai aprender no Nível 2 (UNION ALL); por enquanto, olhe só o resultado.
1. categorias: os departamentos
A tabela mais simples: os 8 departamentos da loja.
| Coluna | O que guarda |
|---|---|
id | O número da categoria (1 a 8) |
nome | O nome do departamento |
descricao | Uma frase curta sobre o departamento |
SELECT * FROM categorias;
2. fornecedores: quem vende para a loja
As 6 empresas que abastecem o estoque. A maioria é brasileira, mas há fornecedores de fora do país.
| Coluna | O que guarda |
|---|---|
id | O número do fornecedor (1 a 6) |
nome | O nome da empresa |
cidade, estado, pais | Onde ela fica (estado é a sigla, como PI) |
telefone | O telefone, em formato brasileiro ou internacional |
SELECT * FROM fornecedores;
Repare em duas coisas, que vão render aulas: as empresas de Portugal e da Argentina não têm estado (aparece NULL), e uma das empresas brasileiras tem um apóstrofo no nome. Como escrever esse nome entre aspas simples sem confundir o SQLite? Você vai descobrir quando chegar a hora.
3. produtos: o estoque
O coração da loja: os 45 produtos à venda, com preço e quantidade na prateleira.
| Coluna | O que guarda |
|---|---|
id | O número do produto (1 a 45) |
nome | O nome do produto |
categoria_id | O id da categoria → tabela categorias |
fornecedor_id | O id do fornecedor → tabela fornecedores |
preco | O preço de hoje, em reais, com ponto decimal (12.35) |
estoque | Quantas unidades há na prateleira |
descontinuado | 1 se o produto saiu de linha, 0 se continua à venda |
SELECT * FROM produtos LIMIT 5;
O LIMIT 5 mostra só os 5 primeiros (aula LIMIT e OFFSET). Leia a linha do lápis: categoria_id 1 (Papelaria) e fornecedor_id 6 (Norte Suprimentos, de Teresina). O descontinuado usa 0 e 1 no lugar de "não" e "sim": o SQLite não tem um tipo próprio para verdadeiro/falso, e esse é o costume (aula Os Tipos no SQLite).
4. clientes: quem compra
Os 30 clientes cadastrados, do Piauí, do Ceará, de Pernambuco e de São Paulo.
| Coluna | O que guarda |
|---|---|
id | O número do cliente (1 a 30) |
nome | O nome completo |
email | O email (todos fictícios, em @exemplo.com.br) |
cidade, estado | Onde mora |
nascimento | A data de nascimento, no formato ano-mês-dia |
vip | 1 se é cliente VIP, 0 se não |
SELECT * FROM clientes LIMIT 5;
A data de nascimento do primeiro cliente está como 1985-03-12, e não "12/03/1985". É o padrão internacional (ISO), e é o que todo banco entende melhor: em ordem alfabética, as datas ficam também em ordem cronológica. As datas têm aulas próprias: Datas e Horas e Funções de Data.
5. funcionarios: a equipe
As 8 pessoas que trabalham na loja, com cargo, salário e chefe.
| Coluna | O que guarda |
|---|---|
id | O número do funcionário (1 a 8) |
nome | O nome |
cargo | Gerente, Supervisora, Vendedor(a) ou Estoquista |
salario | O salário, em reais |
chefe_id | O id do chefe → a própria tabela funcionarios |
SELECT * FROM funcionarios;
O chefe_id é a ligação mais curiosa do banco: ele aponta para outra linha da mesma tabela. O chefe do Igor (id 6) é a funcionária de id 5, a Luana Castelo, supervisora; e o chefe da Luana é a de id 1, a gerente Marta Lustosa. E a Marta? Ela não tem chefe, e o seu chefe_id é NULL. Montar esse "organograma" com uma consulta só é a aula Self Join.
6. pedidos: o talão de vendas
Os 90 pedidos feitos de janeiro de 2024 a outubro de 2026. Cada linha é uma venda: quem comprou, quem atendeu, quando, quando chegou e quanto custou o frete.
| Coluna | O que guarda |
|---|---|
id | O número do pedido (1 a 90) |
cliente_id | Quem comprou → tabela clientes |
funcionario_id | Quem atendeu → tabela funcionarios |
data | A data do pedido (ano-mês-dia) |
entregue_em | A data da entrega |
frete | O valor do frete, em reais |
SELECT * FROM pedidos LIMIT 5;
Repare: o pedido não guarda o que foi comprado, nem o valor total. Um pedido pode ter vários produtos, e uma linha não tem lugar para "vários". Para isso existe a última tabela.
7. itens_pedido: o que foi comprado
Cada linha é um produto dentro de um pedido: "no pedido 1, foram 2 unidades do produto 1, a R$ 12,35 cada". São 220 itens no total.
| Coluna | O que guarda |
|---|---|
pedido_id | De que pedido é este item → tabela pedidos |
produto_id | Que produto foi vendido → tabela produtos |
quantidade | Quantas unidades |
preco_unitario | O preço de cada unidade, no dia da venda |
Esta tabela não tem uma coluna id própria. Quem identifica cada linha é o par pedido_id + produto_id: o mesmo produto não aparece duas vezes no mesmo pedido (se a cliente levou três lápis, é uma linha com quantidade 3). Isso se chama chave primária composta, e você a verá em PRIMARY KEY. Uma tabela assim, que liga duas outras (pedidos e produtos), é o assunto de Relação Muitos-para-Muitos.
E por que guardar o preço de novo, se o produto já tem preco? Porque preços mudam. O preco da tabela de produtos é o de hoje; o preco_unitario é o que o cliente pagou naquele dia. Uma nota fiscal antiga não pode mudar quando a loja reajusta a tabela de preços.
8. Seguindo um pedido de ponta a ponta
Agora junte tudo. Vamos descobrir, só com o que você já viu, a história completa do pedido 1. É um trabalho de detetive: cada resposta dá a pista para a próxima pergunta.
Passo 1: o pedido.
SELECT * FROM pedidos WHERE id = 1;
Foi feito em 5 de janeiro de 2024 e entregue no dia 10, com frete de R$ 9,90. Quem comprou foi o cliente 1, e quem atendeu foi o funcionário 2.
Passo 2: quem comprou e quem atendeu.
SELECT id, nome FROM clientes WHERE id = 1; SELECT id, nome, cargo FROM funcionarios WHERE id = 2;
O José Ribamar Silva foi atendido pelo vendedor Caio Teles.
Passo 3: o que foi comprado.
SELECT * FROM itens_pedido WHERE pedido_id = 1;
Três itens: produtos 1, 2 e 3. Que produtos são esses?
SELECT id, nome, preco FROM produtos WHERE id IN (1, 2, 3);
2 cadernos, 1 caneta azul e 3 lápis: material escolar, bem a tempo da volta às aulas. (O IN (1, 2, 3) quer dizer "o id é 1, 2 ou 3"; aula IN.)
Passo 4: quanto custou. Cada item vale quantidade × preco_unitario: 2 × 12,35 + 1 × 2,79 + 3 × 1,15. O banco faz a conta:
SELECT SUM(quantidade * preco_unitario) FROM itens_pedido WHERE pedido_id = 1;
Os produtos somam R$ 30,94. Com o frete de R$ 9,90, o José pagou R$ 40,84. O SUM ("soma") tem aula própria: SUM().
Foram cinco consultas para uma história. No Nível 2 você vai aprender o JOIN, que junta as tabelas e conta a mesma história numa consulta só. Mas a ideia é exatamente esta: seguir os ids de uma tabela para outra.
Experimente: faça o mesmo trabalho de detetive com o pedido 2. A consulta abaixo mostra o pedido. Rode, veja qual é o funcionario_id e, depois, troque a consulta (ou acrescente outra) para mostrar o nome do funcionário que atendeu.
SELECT * FROM pedidos WHERE id = 2;
SELECT * FROM pedidos WHERE id = 2; SELECT id, nome, cargo FROM funcionarios WHERE id = 3;
9. Os casos especiais (de propósito)
Um banco de verdade nunca é perfeitinho: falta o email de um cliente, um produto encalha, um pedido atrasa. A Loja Aurora foi montada com esses "defeitos" de propósito, para cada aula ter um caso real a resolver. Sem estragar a surpresa, aqui está o que espera por você:
| Caso escondido no banco | Em que tabela | A aula que o encontra |
|---|---|---|
| Clientes que não informaram o email ou o nascimento | clientes | O Valor NULL, IS NULL |
| Cidades que se repetem muito | clientes | SELECT DISTINCT, GROUP BY |
| Duas clientes com o primeiro nome igual | clientes | LIKE |
| Nomes com acento e um nome com apóstrofo | clientes, fornecedores | LIKE, Funções de Texto |
| Clientes cadastrados que nunca compraram | clientes × pedidos | LEFT JOIN |
| Produtos que nunca foram vendidos | produtos × itens_pedido | LEFT JOIN, Subconsultas |
| Produtos que saíram de linha | produtos | WHERE |
| Pedidos que ainda não chegaram | pedidos | IS NULL |
| Pedidos com frete grátis | pedidos | WHERE |
| Vendas feitas em promoção, por um preço diferente do de hoje | itens_pedido × produtos | JOIN |
| Contas com centavos "quebrados" | itens_pedido | Funções Numéricas (ROUND) |
| Fornecedores de fora do Brasil, sem estado | fornecedores | Comparações, IS NULL |
| A gerente, que não tem chefe | funcionarios | Self Join |
| Funcionários que nunca atenderam um pedido | funcionarios × pedidos | LEFT JOIN |
Quem são esses clientes, quais são esses produtos e quantos são os pedidos atrasados? Essas são exatamente as perguntas que você vai aprender a fazer ao banco. Não vale espiar.
10. Formas de explorar o banco
| Onde | Como ver as tabelas | Como ver as colunas | Quando usar |
|---|---|---|---|
| Esta página | O mapa e as seções 1 a 7 | As tabelas de colunas | Consulta rápida enquanto estuda (volte aqui sempre que precisar) |
| Editor do guia | SELECT name FROM sqlite_schema WHERE type = 'table'; | PRAGMA table_info(produtos); | Durante as aulas |
Terminal sqlite3 com o loja.db | .tables | .schema produtos | No seu computador (aula Comandos de Ponto) |
O arquivo aurora.sql | Os CREATE TABLE no começo | Dentro de cada CREATE TABLE | Para ver todos os dados de uma vez, num editor de texto |
O banco pronto, aurora.db | Abra com sqlite3 aurora.db (ou salve como loja.db) e use .tables | .schema | Para ter a loja no seu computador sem montar nada; é o mesmo arquivo que o aurora.sql cria (veja Instalar o SQLite) |
Quando dá errado
SELECT nome, email FROM pedidos;
O que aconteceu: no such column: nome. A Ana queria o nome e o email de quem fez os pedidos, mas a tabela pedidos só guarda o número do cliente (cliente_id). O nome e o email estão em clientes.
Como consertar: procure a coluna na tabela certa (as seções 1 a 7 desta página, ou o .schema). Para juntar dados de duas tabelas numa resposta só, siga o id, como na seção 8, ou espere o JOIN.
SELECT * FROM itens_pedidos;
O que aconteceu: no such table: itens_pedidos. A tabela é itens_pedido: "itens" no plural, "pedido" no singular (os itens de um pedido). Os outros nomes do banco são todos no plural.
Como consertar: SELECT * FROM itens_pedido;. Na dúvida, o mapa do começo da página tem os sete nomes exatos.
SELECT id, data FROM pedidos WHERE data = '05/01/2024';
O que aconteceu: zero linhas, e nenhum erro. O pedido 1 é de 5 de janeiro de 2024, mas a data está guardada como '2024-01-05'. Para o SQLite, '05/01/2024' é só um texto diferente, que não bate com nenhuma linha.
Como consertar: escreva a data como ela está no banco, ano-mês-dia:
SELECT id, data FROM pedidos WHERE data = '2024-01-05';
SELECT nome FROM produtos WHERE preco = 2,79;
O que aconteceu: near ",": syntax error. No SQL, a vírgula separa coisas (colunas, valores); ela nunca é a vírgula dos centavos. O SQLite leu 2, depois uma vírgula fora de lugar, e se perdeu.
Como consertar: ponto decimal, como em 2.79. Os preços da loja estão todos guardados assim.
Referência rápida
| Tabela | Linhas | Colunas | Liga com |
|---|---|---|---|
categorias | 8 | id, nome, descricao | (é apontada por produtos) |
fornecedores | 6 | id, nome, cidade, estado, pais, telefone | (é apontada por produtos) |
produtos | 45 | id, nome, categoria_id, fornecedor_id, preco, estoque, descontinuado | categorias, fornecedores |
clientes | 30 | id, nome, email, cidade, estado, nascimento, vip | (é apontada por pedidos) |
funcionarios | 8 | id, nome, cargo, salario, chefe_id | funcionarios (o chefe) |
pedidos | 90 | id, cliente_id, funcionario_id, data, entregue_em, frete | clientes, funcionarios |
itens_pedido | 220 | pedido_id, produto_id, quantidade, preco_unitario | pedidos, produtos |
| Para saber… | Faça |
|---|---|
| O valor de um item | quantidade * preco_unitario |
| O total de um pedido | A soma dos itens + o frete do pedido |
| Datas | Sempre 'ano-mês-dia', entre aspas simples: '2024-01-05' |
| Dinheiro | Ponto decimal: 2.79 |
| Sim/não | 1 e 0 (vip, descontinuado) |
Exercícios
1. O talão
Complete com o nome da tabela que guarda cada venda (quem comprou, quando, o frete):
2. A ligação com a categoria
Complete com a coluna da tabela produtos que diz a categoria de cada produto:
3. Onde fica guardado o que foi comprado em cada pedido?
4. Por que itens_pedido tem preco_unitario, se o produto já tem preco?
5. Para que serve a coluna chefe_id?
6. A Ana procurou os pedidos de '14/01/2024' e não veio nada, sem erro. Por quê?
Missão final: o chefe da Sofia
Missão: a vendedora Sofia Rocha precisa pedir férias ao chefe dela. Quem é? A consulta abaixo mostra a linha da Sofia, com o chefe_id. Rode, anote o número e acrescente uma segunda consulta que mostre o nome do funcionário com esse id.
SELECT id, nome, cargo, chefe_id FROM funcionarios WHERE nome = 'Sofia Rocha';
SELECT id, nome, cargo, chefe_id FROM funcionarios WHERE nome = 'Sofia Rocha'; SELECT id, nome, cargo FROM funcionarios WHERE id = 5;
Agora você conhece a casa. A partir da próxima aula, SELECT, você começa a fazer as suas próprias perguntas a ela.
Resumo
- Todas as aulas usam o banco da Loja Aurora: dados fictícios e fixos, iguais no editor e no seu
loja.db. - São 7 tabelas:
categorias(8),fornecedores(6),produtos(45),clientes(30),funcionarios(8),pedidos(90) eitens_pedido(220). - Elas se ligam pelos ids: o produto aponta para a categoria e o fornecedor; o pedido, para o cliente e o funcionário; o item, para o pedido e o produto; o funcionário, para o chefe.
- O pedido não guarda o que foi comprado: isso fica em
itens_pedido, com a quantidade e o preço pago. Total = soma dequantidade * preco_unitario+frete. - Datas em
'ano-mês-dia', dinheiro com ponto decimal, sim/não como 1 e 0. - O banco tem casos especiais de propósito (dados faltando, clientes sem pedidos, produtos encalhados, pedidos a caminho…), que as próximas aulas vão encontrar.