SELECT, WHERE e ORDER BY formam o “kit básico” para transformar uma pergunta de negócio em uma consulta que retorna dados úteis, filtrados e organizados. Na prática, a maior parte das análises do dia a dia começa com: (1) escolher quais colunas você precisa (SELECT), (2) restringir o universo de linhas ao que importa (WHERE) e (3) ordenar o resultado para leitura, priorização ou validação (ORDER BY). Este capítulo revisa esses três pontos com foco em perguntas reais de negócio, evitando teoria desnecessária e enfatizando como escrever consultas que você consegue explicar para alguém da área.
SELECT: escolhendo o que você quer ver (e por quê)
O SELECT define quais campos (colunas) vão aparecer no resultado. Em análise de dados, isso é mais do que “mostrar colunas”: é decidir quais evidências você precisa para responder à pergunta. Um SELECT bem feito evita excesso de informação e facilita validar se o filtro está correto.
Selecionando colunas específicas
Prefira listar as colunas necessárias em vez de usar SELECT *. Isso melhora a legibilidade, reduz o volume de dados retornado e diminui o risco de “pegar” colunas que mudam com o tempo.
SELECT order_id, order_date, customer_id, total_amount FROM orders;Esse padrão é útil quando a pergunta é do tipo: “Quais pedidos foram feitos e qual foi o valor total?” Mesmo sem filtro, você já está preparando o terreno para aplicar WHERE e ORDER BY.
Renomeando colunas (aliases) para leitura de negócio
Em relatórios e extrações, aliases tornam o resultado mais claro para quem não conhece o nome técnico da coluna. Use AS (ou apenas um espaço, dependendo do SQL) para renomear.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
SELECT order_id AS pedido, order_date AS data_pedido, total_amount AS valor_total FROM orders;Aliases também ajudam quando você exporta o resultado para uma planilha ou compartilha com outras áreas.
Expressões no SELECT: calculando campos úteis
Nem sempre a coluna que você precisa existe pronta. Você pode criar campos calculados no SELECT, por exemplo para converter valores, criar faixas, ou derivar indicadores simples.
SELECT order_id, total_amount, total_amount * 0.1 AS estimativa_imposto FROM orders;Esse tipo de cálculo é comum em perguntas como: “Qual seria o imposto estimado por pedido?” Mesmo que o cálculo real seja mais complexo, a técnica é a mesma.
SELECT DISTINCT: removendo duplicidades para perguntas de contagem de entidades
Quando a pergunta é “quantos clientes” ou “quais categorias”, você pode precisar listar valores únicos. DISTINCT remove duplicatas no conjunto de colunas selecionadas.
SELECT DISTINCT customer_id FROM orders;Use com cuidado: DISTINCT pode esconder problemas de modelagem ou duplicidade indevida. Em revisão prática, a dica é: use quando a pergunta é sobre “lista única” e você entende por que há repetição.
WHERE: filtrando para responder exatamente à pergunta
O WHERE restringe as linhas retornadas. Em termos de negócio, ele define o “escopo” da análise: período, região, status, canal, categoria, faixa de preço, etc. Um bom WHERE é específico, testável e alinhado com a pergunta.
Filtros básicos com operadores de comparação
Os operadores mais comuns são: =, <> (diferente), >, >=, <, <=.
SELECT order_id, order_date, total_amount FROM orders WHERE total_amount >= 500;Exemplo de pergunta: “Quais pedidos tiveram valor igual ou acima de 500?” Esse tipo de filtro é útil para identificar pedidos de alto valor, checar políticas de frete grátis, ou priorizar atendimento.
Combinando condições com AND e OR
Negócio raramente filtra por um único critério. Você combina condições com AND (todas devem ser verdadeiras) e OR (qualquer uma pode ser verdadeira). Use parênteses para deixar explícita a lógica.
SELECT order_id, order_date, channel, total_amount FROM orders WHERE channel = 'online' AND total_amount > 200;Pergunta: “Quais pedidos online acima de 200?” Aqui, o AND garante que você não misture pedidos de outros canais.
SELECT order_id, order_date, status FROM orders WHERE status = 'paid' OR status = 'shipped';Pergunta: “Quais pedidos já foram pagos ou enviados?” Esse OR é comum em monitoramento operacional.
Armadilha frequente: misturar AND e OR sem parênteses e obter um resultado maior (ou menor) do que o esperado. Compare:
-- Pode dar resultado inesperado dependendo da precedência do SQL (AND antes de OR) SELECT order_id, status, channel FROM orders WHERE status = 'paid' OR status = 'shipped' AND channel = 'online';-- Mais claro: primeiro define o conjunto de status, depois restringe ao canal online SELECT order_id, status, channel FROM orders WHERE (status = 'paid' OR status = 'shipped') AND channel = 'online';Para perguntas de negócio, a versão com parênteses é mais fácil de explicar e revisar.
Filtrando por intervalo: BETWEEN (e alternativas)
BETWEEN é útil para intervalos numéricos e de datas. Em muitos bancos, ele é inclusivo nas extremidades (inclui o início e o fim).
SELECT order_id, order_date, total_amount FROM orders WHERE total_amount BETWEEN 100 AND 300;Pergunta: “Pedidos entre 100 e 300.”
Para datas, um cuidado prático: se order_date tiver hora (timestamp), filtrar “até o fim do dia” pode exigir atenção. Uma abordagem robusta é usar intervalo semiaberto (maior ou igual ao início e menor que o dia seguinte), quando aplicável:
SELECT order_id, order_date FROM orders WHERE order_date >= '2025-01-01' AND order_date < '2025-02-01';Pergunta: “Pedidos de janeiro.” Esse padrão evita perder registros do último dia por causa de horário.
Listas de valores: IN
Quando o negócio define um conjunto de valores permitidos (ex.: status relevantes, regiões específicas), IN deixa a consulta mais limpa do que vários OR.
SELECT order_id, status FROM orders WHERE status IN ('paid', 'shipped', 'delivered');Pergunta: “Pedidos em status considerados ‘ativos’.”
Texto e padrões: LIKE
LIKE permite filtrar por padrões em texto. O caractere % representa “qualquer sequência de caracteres” e _ representa “um caractere”. Use para buscas simples (ex.: e-mails, nomes, códigos).
SELECT customer_id, email FROM customers WHERE email LIKE '%@empresa.com';Pergunta: “Quais clientes têm e-mail corporativo?”
Boas práticas: evite usar LIKE com % no início em tabelas muito grandes quando performance for crítica, pois pode impedir o uso de índices. Em revisão prática, o foco é: use quando necessário e valide com uma amostra.
Valores ausentes: IS NULL e IS NOT NULL
Em SQL, NULL não é igual a nada, nem a outro NULL. Por isso, você não usa = NULL. Use IS NULL ou IS NOT NULL.
SELECT order_id, shipped_date FROM orders WHERE shipped_date IS NULL;Pergunta: “Quais pedidos ainda não foram enviados (sem data de envio)?”
Esse tipo de filtro é muito comum em auditoria operacional e em checagens de qualidade de dados.
Negação: NOT (com cuidado)
NOT inverte uma condição. É útil para excluir um conjunto, mas exige atenção com NULLs e com a lógica. Exemplos:
SELECT order_id, status FROM orders WHERE status NOT IN ('canceled', 'refunded');Pergunta: “Pedidos que não são cancelados nem reembolsados.”
Se a coluna status puder ser NULL, o comportamento pode surpreender dependendo do banco. Uma forma mais explícita é combinar com IS NOT NULL quando fizer sentido:
SELECT order_id, status FROM orders WHERE status IS NOT NULL AND status NOT IN ('canceled', 'refunded');ORDER BY: organizando para leitura, priorização e validação
ORDER BY define a ordem das linhas no resultado. Para perguntas de negócio, ordenar é essencial para: (1) ver “top” e “bottom”, (2) encontrar outliers, (3) validar se o filtro trouxe o período correto, (4) preparar uma exportação que já vem organizada.
Ordenação ascendente e descendente
Por padrão, ORDER BY é ascendente (ASC). Para ver maiores valores primeiro, use DESC.
SELECT order_id, order_date, total_amount FROM orders ORDER BY order_date ASC;SELECT order_id, order_date, total_amount FROM orders ORDER BY total_amount DESC;Perguntas típicas: “Quais os pedidos mais recentes?” (order_date DESC) e “Quais os maiores pedidos?” (total_amount DESC).
Ordenando por múltiplas colunas
Você pode ordenar por mais de uma coluna para desempate. Isso é útil quando você quer agrupar visualmente por um critério e, dentro dele, ordenar por outro.
SELECT order_id, status, order_date, total_amount FROM orders ORDER BY status ASC, order_date DESC;Pergunta: “Dentro de cada status, quais são os pedidos mais recentes?”
Ordenando por posição (quando usar e quando evitar)
Alguns bancos permitem ordenar pelo número da coluna no SELECT (ex.: ORDER BY 3). Isso pode ser prático em consultas rápidas, mas reduz a legibilidade e quebra facilmente quando você altera o SELECT. Para análises do dia a dia que serão reutilizadas, prefira ordenar pelo nome/alias.
SELECT order_id, order_date, total_amount FROM orders ORDER BY total_amount DESC;ORDER BY para validação rápida do filtro
Um uso muito prático: após escrever um WHERE, ordenar por data ou por valor ajuda a verificar se você trouxe o intervalo correto e se não há registros estranhos.
SELECT order_id, order_date, total_amount FROM orders WHERE order_date >= '2025-01-01' AND order_date < '2025-02-01' ORDER BY order_date ASC;Ao olhar o primeiro e o último registro, você confirma rapidamente se a janela de tempo está correta.
Passo a passo: transformando perguntas de negócio em consultas
A seguir, um roteiro prático para sair da pergunta e chegar a um SQL correto usando SELECT, WHERE e ORDER BY. A ideia é você repetir esse processo sempre, reduzindo erros e retrabalho.
Passo a passo 1: “Quais foram os 20 pedidos de maior valor no mês passado?”
1) Esclareça a pergunta em termos de dados: você precisa de pedidos, valor total, data do pedido. Precisa filtrar por período (mês passado) e ordenar por valor desc. Precisa limitar a 20 linhas (o LIMIT/TOP pode variar por banco; aqui vamos focar nos três comandos, mas a limitação é parte comum do uso).
2) Comece com um SELECT mínimo (colunas essenciais):
SELECT order_id, order_date, total_amount FROM orders;3) Adicione o WHERE do período (exemplo com intervalo fechado no mês):
SELECT order_id, order_date, total_amount FROM orders WHERE order_date >= '2025-12-01' AND order_date < '2026-01-01';4) Adicione ORDER BY para priorizar os maiores valores:
SELECT order_id, order_date, total_amount FROM orders WHERE order_date >= '2025-12-01' AND order_date < '2026-01-01' ORDER BY total_amount DESC;5) (Opcional) Limite para 20 (ajuste ao seu banco):
SELECT order_id, order_date, total_amount FROM orders WHERE order_date >= '2025-12-01' AND order_date < '2026-01-01' ORDER BY total_amount DESC LIMIT 20;Checagens rápidas: ordene também por data como desempate se houver valores iguais; verifique se total_amount não está nulo; confirme se o período está correto para o fuso/horário do dado.
Passo a passo 2: “Quais clientes fizeram compras acima de 1000 e em quais datas?”
1) Traduza a pergunta: você precisa de customer_id, data do pedido e valor. Filtro por valor > 1000. Ordenação pode ser por cliente e depois por data.
2) SELECT com colunas relevantes:
SELECT customer_id, order_date, total_amount FROM orders;3) WHERE para o critério de valor:
SELECT customer_id, order_date, total_amount FROM orders WHERE total_amount > 1000;4) ORDER BY para leitura por cliente:
SELECT customer_id, order_date, total_amount FROM orders WHERE total_amount > 1000 ORDER BY customer_id ASC, order_date ASC;Checagens rápidas: se o objetivo for “clientes” (lista única), você pode usar DISTINCT em customer_id, mas isso perderia as datas. Para manter as datas, o resultado deve ter múltiplas linhas por cliente.
Passo a passo 3: “Quais pedidos estão atrasados para envio?”
1) Defina a regra: “atrasado” pode significar: status ainda não enviado e data prevista de envio menor que hoje. Suponha colunas status, expected_ship_date, shipped_date.
2) SELECT para operação (o que a equipe precisa ver):
SELECT order_id, status, expected_ship_date, shipped_date FROM orders;3) WHERE com lógica de atraso: ainda não enviado (shipped_date IS NULL) e expected_ship_date < hoje. A função de data “hoje” varia; aqui usamos um placeholder.
SELECT order_id, status, expected_ship_date, shipped_date FROM orders WHERE shipped_date IS NULL AND expected_ship_date < CURRENT_DATE;4) ORDER BY para priorizar os mais antigos:
SELECT order_id, status, expected_ship_date, shipped_date FROM orders WHERE shipped_date IS NULL AND expected_ship_date < CURRENT_DATE ORDER BY expected_ship_date ASC;Checagens rápidas: confirme se há pedidos com expected_ship_date nula; se houver, decida se entram ou não (ex.: expected_ship_date IS NOT NULL).
Passo a passo 4: “Quais produtos tiveram queda de vendas em um período específico?” (recorte inicial com SELECT/WHERE/ORDER BY)
Uma análise completa de queda normalmente envolve agregações e comparação entre períodos. Aqui, o objetivo é mostrar como preparar o recorte inicial para inspeção: filtrar o período e ordenar para encontrar candidatos a queda (por exemplo, olhando transações por produto).
1) Defina o recorte: período e colunas de interesse. Suponha uma tabela order_items com product_id, order_date, quantity, unit_price.
2) SELECT com colunas que permitem investigar:
SELECT product_id, order_date, quantity, unit_price FROM order_items;3) WHERE para o período:
SELECT product_id, order_date, quantity, unit_price FROM order_items WHERE order_date >= '2025-10-01' AND order_date < '2025-11-01';4) ORDER BY para leitura por produto e data:
SELECT product_id, order_date, quantity, unit_price FROM order_items WHERE order_date >= '2025-10-01' AND order_date < '2025-11-01' ORDER BY product_id ASC, order_date ASC;Esse resultado não “prova” queda, mas cria uma base para você observar padrões e preparar o próximo passo (agregação por produto e comparação de períodos) em capítulos que tratem de GROUP BY e métricas.
Perguntas de negócio comuns e padrões de consulta
Os padrões abaixo ajudam a reconhecer rapidamente qual combinação de SELECT/WHERE/ORDER BY usar.
“Quais são os registros mais recentes?”
SELECT id, created_at, status FROM tickets WHERE status = 'open' ORDER BY created_at DESC;Use ORDER BY DESC em data/hora. Se houver muitos registros, normalmente você combina com um limite.
“Quais são os maiores/menores valores?”
SELECT invoice_id, customer_id, amount FROM invoices WHERE amount IS NOT NULL ORDER BY amount DESC;Inclua IS NOT NULL quando valores ausentes podem atrapalhar a leitura.
“Quais itens estão fora do padrão (outliers simples)?”
SELECT transaction_id, transaction_date, amount FROM transactions WHERE amount > 10000 ORDER BY amount DESC;O WHERE define o “fora do padrão” com um limiar simples; ORDER BY ajuda a ver os casos extremos primeiro.
“Quais registros pertencem a um conjunto de categorias prioritárias?”
SELECT product_id, category, price FROM products WHERE category IN ('Acessorios', 'Eletronicos', 'Casa') ORDER BY category ASC, price DESC;IN deixa o filtro mais legível e fácil de manter quando a lista muda.
“Quais registros têm dados faltantes que precisam de correção?”
SELECT customer_id, name, email FROM customers WHERE email IS NULL ORDER BY customer_id ASC;Esse padrão é útil para rotinas de qualidade: localizar e priorizar correções.
Checklist prático para evitar erros (SELECT/WHERE/ORDER BY)
- Comece simples: escreva um SELECT com poucas colunas e rode antes de adicionar filtros complexos.
- Valide o WHERE com ORDER BY: ordene por data e confira o primeiro/último registro do intervalo.
- Use parênteses com AND/OR: deixe a lógica explícita para você e para quem vai revisar.
- Trate NULLs conscientemente: use IS NULL/IS NOT NULL e pense se valores ausentes devem entrar ou sair.
- Evite SELECT * em consultas que serão reutilizadas: prefira colunas explícitas e aliases claros.
- Ordene com intenção: se a pergunta é “top”, use DESC; se é “fila operacional”, use ASC para priorizar os mais antigos.