O que você vai
saber fazer.
Objetivos da Aula — Taxonomia de Bloom
Lembrar Reconhecer os cinco comandos SQL fundamentais — SELECT, FROM, WHERE, JOIN e GROUP BY — e seus propósitos básicos.
Compreender Explicar como cada cláusula SQL transforma os dados para responder uma pergunta de negócio específica.
Aplicar Escrever consultas com SELECT, WHERE, JOIN e GROUP BY para extrair informações de um banco relacional normalizado.
Analisar Interpretar o resultado de uma consulta e diagnosticar por que uma query retorna dados errados ou gera erros de sintaxe.
Avaliar Julgar se a resposta retornada por uma query — inclusive gerada por IA — responde corretamente a pergunta de negócio original.
Quem vai buscar
as respostas?
SQL é quase português — leia em voz alta
-- SELECIONE o nome dos artistas SELECT artista_nome -- DA tabela artistas FROM artistas -- ONDE o gênero seja MPB WHERE artista_genero = 'MPB';

Clientes inativos

Quais clientes não compram há mais de seis meses? Marketing precisa da lista para a campanha de reativação.

Artistas em crescimento

Quais artistas tiveram crescimento de receita nos últimos 12 meses? Curadoria precisa renovar contratos.

Ticket médio por país

Quais países têm o maior ticket médio? Expansão precisa definir mercados prioritários.

SQL como alfabetização

SQL é quase português. Uma query pode ser lida em voz alta e compreendida por quem nunca programou — o ponto é esse.

Os 5 comandos do dia a dia

SELECT · FROM · WHERE · JOIN · GROUP BY resolvem 80% das perguntas analíticas de uma empresa. Os outros 20% são variações.

Humano valida, IA gera

A IA pode gerar código correto que responde a pergunta errada. A curadoria analítica ainda é humana.

Do caos à consulta:
7 tabelas.
✗ Antes — 1 tabela, 23 colunas
  • pedido_id, pedido_data
  • cliente_id, cliente_nome, cliente_email, cliente_pais, cliente_cidade
  • artista_id, artista_nome, artista_genero, artista_pais_origem
  • faixa_id, faixa_titulo, album_id, album_titulo, album_ano, faixa_duracao_seg, faixa_preco_usd, faixa_formato
  • gravadora_id, gravadora_nome
  • qtd_comprada, total_pedido_usd

Anomalias de inserção, alteração e exclusão. Ana Lima com dois IDs. Preço zerado em 4 linhas.

✓ Depois — 7 tabelas relacionadas
  • clientes
  • artistas
  • gravadoras
  • albuns
  • faixas
  • pedidos
  • itens_pedido

Cada entidade em sua tabela. PKs e FKs garantem integridade. Preço centralizado em faixas.

Schema PostgreSQL — SoundByte
clientes
PK cliente_id
cliente_nome
cliente_email
cliente_pais
cliente_cidade
artistas
PK artista_id
artista_nome
artista_genero
artista_pais_origem
gravadoras
PK gravadora_id
gravadora_nome
albuns
PK album_id
album_titulo
album_ano
FK artista_id
FK gravadora_id
faixas
PK faixa_id
faixa_titulo
faixa_duracao_seg
faixa_preco_usd
faixa_formato
FK album_id
pedidos
PK pedido_id
pedido_data
FK cliente_id
itens_pedido
FK pedido_id
FK faixa_id
qtd_comprada
total_item_usd
DDL — Schema completo SoundByte (PostgreSQL)
CREATE TABLE clientes ( cliente_id SERIAL PRIMARY KEY, cliente_nome VARCHAR(100) NOT NULL, cliente_email VARCHAR(100) UNIQUE NOT NULL, cliente_pais VARCHAR(50), cliente_cidade VARCHAR(50) ); CREATE TABLE artistas ( artista_id SERIAL PRIMARY KEY, artista_nome VARCHAR(100) NOT NULL, artista_genero VARCHAR(50), artista_pais_origem VARCHAR(50) ); CREATE TABLE gravadoras ( gravadora_id SERIAL PRIMARY KEY, gravadora_nome VARCHAR(100) NOT NULL ); CREATE TABLE albuns ( album_id SERIAL PRIMARY KEY, album_titulo VARCHAR(150) NOT NULL, album_ano SMALLINT, artista_id INTEGER REFERENCES artistas(artista_id), gravadora_id INTEGER REFERENCES gravadoras(gravadora_id) ); CREATE TABLE faixas ( faixa_id SERIAL PRIMARY KEY, faixa_titulo VARCHAR(200) NOT NULL, faixa_duracao_seg INTEGER, faixa_preco_usd NUMERIC(6,2) NOT NULL, faixa_formato VARCHAR(10), album_id INTEGER REFERENCES albuns(album_id) ); CREATE TABLE pedidos ( pedido_id SERIAL PRIMARY KEY, pedido_data DATE NOT NULL, cliente_id INTEGER REFERENCES clientes(cliente_id) ); CREATE TABLE itens_pedido ( pedido_id INTEGER REFERENCES pedidos(pedido_id), faixa_id INTEGER REFERENCES faixas(faixa_id), qtd_comprada INTEGER DEFAULT 1, total_item_usd NUMERIC(6,2), PRIMARY KEY (pedido_id, faixa_id) );
DDL
Data Definition Language — comandos que criam e alteram a estrutura do banco (CREATE, ALTER, DROP).
DML
Data Manipulation Language — comandos que movimentam dados (INSERT, UPDATE, DELETE, SELECT).
REFERENCES
Declara a FK e delega ao SGBD a responsabilidade de garantir a integridade referencial automaticamente.
Escolha o quê
e de onde.
SELECT cliente_nome Quais colunas mostrar FROM clientes Qual tabela consultar RESULTADO Carlos Mendes Julia Ferreira Emma Clarke
Selecionar colunas específicas
SELECT cliente_nome, cliente_email, cliente_pais FROM clientes;
Resultado
cliente_nomecliente_emailcliente_pais
Carlos Mendescarlos@email.comBrasil
Julia Ferreirajulia@email.comBrasil
Emma Clarkeemma@email.comUK
Yuki Tanakayuki@email.comJapão
Selecionar colunas e ordenar por preço
SELECT faixa_titulo, faixa_preco_usd, faixa_formato FROM faixas ORDER BY faixa_preco_usd DESC;
Resultado — faixas mais caras primeiro
faixa_titulofaixa_preco_usdfaixa_formato
Milonga Infinita4.99MP3
Nacht Signal4.49FLAC
Saudade Eterna3.99MP3
Foggy Days3.99AAC
Teranga1.99MP3
SELECT *
O asterisco retorna todas as colunas. Útil para explorar, mas evite em produção — traz dados desnecessários e sobrecarrega o banco.
ORDER BY
Ordena o resultado. ASC (padrão, crescente) ou DESC (decrescente).
Alias com AS
SELECT faixa_preco_usd AS preco renomeia a coluna no resultado, útil para relatórios mais legíveis.
Filtre e cruze.
A resposta está em duas tabelas.
CLIENTES CLIENTE_ID NOME PAÍS PK 5001 Carlos Brasil 5002 Julia Brasil 5004 Emma UK JOIN cliente_id PEDIDOS PED_ID CLI_ID DATA TOTAL PK FK 1001 5001 2024-03-01 2.99 1002 5002 2024-03-02 6.98 1006 5001 2024-03-06 2.99
WHERE — Clientes do Brasil
SELECT cliente_nome, cliente_email FROM clientes WHERE cliente_pais = 'Brasil';
JOIN — Pedidos com nome do cliente e valor
SELECT p.pedido_id, p.pedido_data, c.cliente_nome, c.cliente_pais, ip.total_item_usd FROM pedidos p JOIN clientes c ON p.cliente_id = c.cliente_id JOIN itens_pedido ip ON p.pedido_id = ip.pedido_id WHERE p.pedido_data >= '2024-03-01' ORDER BY p.pedido_data;
Respondendo a pergunta — Clientes sem compra há 6 meses
SELECT c.cliente_nome, c.cliente_email, MAX(p.pedido_data) AS ultima_compra FROM clientes c LEFT JOIN pedidos p ON c.cliente_id = p.cliente_id GROUP BY c.cliente_id, c.cliente_nome, c.cliente_email HAVING MAX(p.pedido_data) < CURRENT_DATE - INTERVAL '180 days' OR MAX(p.pedido_data) IS NULL ORDER BY ultima_compra ASC;
WHERE
Filtra linhas antes de retornar o resultado. Equivale a filtrar por data no Excel. Operadores: =, >, <, <>, BETWEEN, LIKE, IN, AND, OR.
INNER JOIN
Retorna apenas as linhas que têm correspondência nas duas tabelas. É o JOIN padrão — equivale a cruzar duas planilhas pelo ID do cliente.
LEFT JOIN
Retorna todas as linhas da tabela da esquerda, mesmo sem correspondência na direita. Útil para encontrar clientes sem pedidos (NULL).
Agrupe para
enxergar padrões.
SEM GROUP BY PAÍS TOTAL Brasil 2.99 Brasil 6.98 UK 3.99 Brasil 2.99 GROUP BY cliente_pais COM GROUP BY PAÍS PEDIDOS TICKET MÉD. Brasil 18 4.12 UK 4 3.99 Japão 3 4.65
Respondendo a pergunta — Ticket médio por país
SELECT c.cliente_pais, COUNT(DISTINCT p.pedido_id) AS total_pedidos, ROUND(SUM(ip.total_item_usd), 2) AS receita_total, ROUND(AVG(ip.total_item_usd), 2) AS ticket_medio FROM clientes c JOIN pedidos p ON c.cliente_id = p.cliente_id JOIN itens_pedido ip ON p.pedido_id = ip.pedido_id WHERE c.cliente_pais IS NOT NULL GROUP BY c.cliente_pais ORDER BY ticket_medio DESC;
Resultado parcial
cliente_paistotal_pedidosreceita_totalticket_medio
Japão317.945.98
Alemanha211.465.73
Argentina29.984.99
Brasil1857.843.21
Funções de agregação
COUNT conta linhas · SUM soma · AVG média · MAX/MIN extremos. Sempre usadas com GROUP BY ou aplicadas a toda a tabela.
HAVING vs WHERE
WHERE filtra antes da agregação (linha por linha). HAVING filtra depois — é o WHERE dos grupos. Ex.: HAVING COUNT(*) > 5
A tabela dinâmica do SQL
GROUP BY é a SQL equivalente de arrastar um campo para "Linhas" no pivot e outro para "Valores". A diferença: é reproduzível, auditável e escalável.
A IA escreve.
Você valida.
O que a IA faz bem
  • Gerar queries sintaticamente corretas a partir de uma descrição em português
  • Identificar erros de sintaxe em queries quebradas
  • Sugerir índices e otimizações de performance
  • Explicar o que cada cláusula de uma query faz
  • Converter queries entre dialetos (PostgreSQL, MySQL, SQLite)
O que o humano deve validar
  • Se a query responde a pergunta de negócio certa — não apenas a pergunta literal
  • Se os JOINs estão duplicando ou perdendo linhas
  • Se o filtro de data usa o campo correto da tabela correta
  • Se o resultado faz sentido no contexto do negócio
  • Se há valores NULL afetando a média ou o total
Exemplo de bom prompt para a IA
Tenho um banco PostgreSQL com as tabelas: - clientes (cliente_id, cliente_nome, cliente_pais) - pedidos (pedido_id, cliente_id, pedido_data) - itens_pedido (pedido_id, faixa_id, total_item_usd) Escreva uma query que retorne os 5 países com maior ticket médio por pedido, excluindo clientes sem país cadastrado. Ordene do maior para o menor.
Regra de ouro: quanto mais contexto você dá à IA (nomes reais das tabelas, colunas existentes, o que a query deve responder), mais precisa e validável fica a resposta.
Query com erros — exercício em sala
-- Pergunta: Quais os artistas com maior receita em 2024? -- Esta query tem 3 erros. Use a IA para encontrá-los. SELECT ar.Name AS artista, SUM(il.UnitPrice * il.Quantity) AS receita FROM Artist ar JOIN Album al ON ar.ArtistId = al.ArtistId JOIN Track t ON al.AlbumId = t.AlbumId JOIN InvoiceLine il ON t.TrackId = il.TrackId WHERE il.InvoiceDate > '2024-01-01' -- Erro 1 GROUP BY ar.Name ORDERED BY receita DESC -- Erro 2 LIMIT 10; -- Erro 3 (lógico)
Erro 1 — Campo errado
InvoiceDate pertence à tabela Invoice, não a InvoiceLine. Falta o JOIN com Invoice na query.
Erro 2 — Sintaxe
ORDERED BY não existe em SQL. O comando correto é ORDER BY. O banco retorna erro imediatamente.
Erro 3 — Lógico
Sem o JOIN com Invoice, a query não filtra por data e retorna receita histórica completa, não apenas de 2024 — a resposta parece correta mas está errada.
Responda com
dados.
SCHEMA CHINOOK — TABELAS PRINCIPAIS ARTIST ArtistId · Name ALBUM AlbumId · Title · ArtistId TRACK TrackId · Name AlbumId · UnitPrice INVOICELINE InvoiceLineId InvoiceId · TrackId INVOICE InvoiceId · CustomerId InvoiceDate · Total CUSTOMER CustomerId Country · Email
1
Acesse o SQLite Online
Abra o navegador e acesse o ambiente de consulta online. Nenhuma instalação necessária.
Abrir SQLite Online ↗
2
Carregue o dataset Chinook
Clique em File → Open DB e selecione o arquivo Chinook_Sqlite.sql fornecido pelo professor. O banco será carregado automaticamente com 11 tabelas e dados reais.
3
Execute as consultas dos exercícios abaixo
Cole cada query na área de texto, clique em Run e analise o resultado. Anote o que cada coluna representa e se a resposta faz sentido de negócio.
4
Exercício de IA: debug da query quebrada
Cole a "query com erros" da página anterior no ChatGPT com o prompt: "Esta query SQL tem erros. Identifique cada erro, explique o que está errado e mostre a versão corrigida." Compare a resposta com o gabarito do professor.
Exercícios — Chinook
Exercício 1
Quais são os 10 artistas com maior receita total de vendas?
Tabelas: ArtistAlbumTrackInvoiceLine · Função: SUM(UnitPrice * Quantity) · Ordenar: DESC
Exercício 2
Qual o ticket médio por país dos clientes? Ordene do maior para o menor.
Tabelas: CustomerInvoice · Função: AVG(Total) agrupado por Country · Excluir países com NULL
Exercício 3
Quais clientes não compraram após 2013? Liste nome, país e data da última compra.
Tabelas: CustomerInvoice · Condição: MAX(InvoiceDate) < '2014-01-01' com HAVING · Ordenar pela data mais antiga
Exercício 4 — Desafio
Para cada país, qual é o artista com maior número de faixas vendidas?
Requer: CustomerInvoiceInvoiceLineTrackAlbumArtist · Agrupe por Country e ArtistId · Use subquery ou CTE para pegar o top 1 por país
Query de referência — Exercício 1 (gabarito)
SELECT ar.Name AS artista, ROUND(SUM(il.UnitPrice * il.Quantity), 2) AS receita FROM Artist ar JOIN Album al ON ar.ArtistId = al.ArtistId JOIN Track t ON al.AlbumId = t.AlbumId JOIN InvoiceLine il ON t.TrackId = il.TrackId GROUP BY ar.ArtistId, ar.Name ORDER BY receita DESC LIMIT 10;
Chinook
Base de dados fictícia de uma loja de música digital. 275 artistas, 347 álbuns, 3.503 faixas e 412 clientes em 24 países. Estrutura similar ao Spotify no início.
SQLite Online
Ambiente SQL no navegador — sem instalação. Suporta SQLite com sintaxe muito similar ao PostgreSQL para os comandos desta aula.
Integração com IA
Ao pedir ajuda à IA, descreva as tabelas, as colunas e a pergunta de negócio. Quanto mais contexto, mais precisa e validável a query gerada.