Revisão prática de SELECT, WHERE e ORDER BY para perguntas de negócio

Capítulo 2

Tempo estimado de leitura: 14 minutos

+ Exercício

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.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

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.

Agora responda o exercício sobre o conteúdo:

Ao filtrar pedidos de janeiro em uma coluna de data que pode incluir hora, qual abordagem tende a ser mais robusta para não perder registros do último dia?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Quando a coluna pode ter horario, o intervalo semiaberto (>= inicio e < dia seguinte/mes seguinte) evita excluir registros do ultimo dia que ocorram apos 00:00. Isso torna o filtro de periodo mais confiavel.

Próximo capitúlo

Filtragem correta, tratamento de nulos e armadilhas comuns em condições

Arrow Right Icon
Capa do Ebook gratuito SQL para Análise de Dados no Dia a Dia: Consultas, Relatórios e Insights com Dados Reais
8%

SQL para Análise de Dados no Dia a Dia: Consultas, Relatórios e Insights com Dados Reais

Novo curso

26 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.