SELECT: extraindo os dados certos

WHERE: só as linhas necessárias

21 min
O que você vai aprender
  • entender que o WHERE filtra linhas, e não colunas;
  • distinguir a escolha de colunas pelo SELECT da seleção de linhas pelo WHERE;
  • escrever condições com os operadores de comparação: =, <>, <, >, <=, >=;
  • combinar condições com AND e OR;
  • posicionar corretamente os parênteses em condições mistas;
  • entender por que o AND é avaliado antes do OR;
  • encontrar erros lógicos silenciosos nas consultas;
  • entender por que NULL não se verifica com = NULL.

WHERE: o feixe que deixa passar só as linhas necessárias

Atrás do terminal fica o depósito: escuridão por milhares de linhas.
Iluminar tudo de uma vez não adianta: dados demais cegam tanto quanto o escuro.

O arquivista não precisa de um refletor, e sim de um feixe. Estreito, bem apontado, honesto. Um feixe que não mostra tudo de uma vez, mas ajuda a achar só o que interessa.

Em SQL, esse feixe se chama WHERE.

O comando SELECT responde à pergunta:

O que mostrar no resultado?

Já o WHERE responde a outra pergunta:

Quais linhas podem entrar no resultado?

Essa diferença é muito importante.

Veja esta consulta, por exemplo:

SELECT name, price
FROM products;

Ela diz ao banco:

Pegue a tabela products e mostre dela as colunas name e price.

Mas, se você acrescentar o WHERE:

SELECT name, price
FROM products
WHERE price > 4000;

o sentido muda:

Pegue a tabela products, confira cada linha e mostre só os itens cujo preço é maior que 4000.

O WHERE não escolhe colunas.
O WHERE escolhe linhas.

As colunas que vão aparecer no resultado são definidas na parte do SELECT.
E as linhas que vão chegar ao resultado são definidas na parte do WHERE.


O feixe de uma lanterna-filtro no depósito escuro: por ele passam apenas algumas cápsulas luminosas de linhas
O WHERE é um feixe no depósito escuro: cada linha é testada pela condição, e poucas chegam à saída.

A estrutura básica de uma consulta com WHERE

Normalmente, uma consulta com filtragem tem esta cara:

SELECT column_1, column_2
FROM table_name
WHERE condition;

Vamos por partes:

SELECT name, price
FROM products
WHERE price > 4000;
  • SELECT name, price — quais dados mostrar no resultado;
  • FROM products — de qual tabela vêm as linhas;
  • WHERE price > 4000 — quais linhas manter;
  • price > 4000 — a condição verificada em cada linha.

O banco percorre mentalmente as linhas da tabela products e, para cada uma, faz a pergunta:

Esta linha tem price > 4000?

Se a resposta for TRUE, a linha entra no resultado.
Se a resposta for FALSE, a linha é descartada.

Importante: o WHERE não apaga linhas da tabela.
Ele apenas deixa de mostrar, no resultado daquela consulta, as linhas que não se encaixam.

A tabela continua exatamente como era.


WHEREpassed
A peneira WHERE: a condição é avaliada linha por linha, e só entram no resultado as linhas cuja resposta é TRUE.

Toda consulta devolve uma nova tabela de resultado

Quando você escreve uma consulta SQL, o banco não se limita a “mostrar um pedaço da tabela”.
Ele monta o resultado da consulta — uma tabela temporária, que é o que você vê na tela.

Por exemplo:

SELECT name, price
FROM products
WHERE price > 4000;

pode devolver este resultado:

nameprice
Projetor holográfico7800
Neurointerface de treinamento12500
Escâner portátil de matéria5600

Essa tabela de resultado tem apenas duas colunas: name e price.

Mas a filtragem aconteceu pela coluna price.

Ou seja, a coluna price cumpriu dois papéis ao mesmo tempo:

  • participou da verificação da condição;
  • apareceu no resultado.

Mas nem sempre é assim.

Dá para filtrar linhas por uma coluna que você não mostra no resultado:

SELECT name, price
FROM products
WHERE stock < 60;

Aqui o resultado traz apenas name e price, mas o banco continua usando a coluna stock para decidir quais linhas manter.

Isso é normal e muito comum.

O WHERE pode verificar uma coluna mesmo que ela não esteja no SELECT.


Operadores de comparação

No WHERE, os operadores de comparação são os mais usados.

Eles ajudam a verificar se o valor de uma linha se encaixa na condição desejada.

Os principais operadores:

OperadorSignificadoExemplo
=igual acategory = 'Книги'
<>diferente destatus <> 'cancelled'
>maior queprice > 4000
<menor questock < 60
>=maior ou igual arating >= 4.5
<=menor ou igual astock <= 10

Exemplos:

SELECT name, category
FROM products
WHERE category = 'Книги';

Mostra apenas os itens da categoria “Livros”.

SELECT name, status
FROM orders
WHERE status <> 'cancelled';

Mostra os pedidos cujo status é diferente de cancelled.

SELECT name, price
FROM products
WHERE price <= 1500;

Mostra os itens com preço de 1500 ou menos.

Repare: os valores de texto vão entre aspas simples:

WHERE category = 'Книги'

Já os números costumam ir sem aspas:

WHERE price > 4000

Não escreva assim:

WHERE category = Книги

Para o SQL, a palavra Книги sem aspas não parece um texto, e sim o nome de uma coluna ou de outro objeto. Por isso o texto precisa de aspas.


Importante: em SQL, a igualdade é verificada com um único sinal =.

Certo:

WHERE status = 'paid'

Errado:

WHERE status == 'paid'

Em algumas linguagens de programação, a comparação se escreve com ==, mas em SQL a forma padrão é =.


Várias condições: AND e OR

Muitas vezes, uma condição só não basta.

Um comprador, por exemplo, pode querer encontrar não só itens caros, mas itens caros que estão acabando.

É para isso que servem os operadores lógicos:

  • AND — “e”;
  • OR — “ou”.

AND: todas as condições precisam ser atendidas

SELECT name, price, stock
FROM products
WHERE price > 4000 AND stock < 60;

Essa consulta mostra apenas as linhas em que, ao mesmo tempo:

  • price > 4000;
  • stock < 60.

Ou seja, o item precisa ser caro e ter pouco estoque.

Se o preço for maior que 4000, mas o estoque for 200, a linha não passa.
Se o estoque for menor que 60, mas o preço for 900, a linha também não passa.

O AND é rigoroso.
Ele deixa a linha passar somente quando todas as condições são atendidas.


OR: basta uma condição

SELECT name, category, price
FROM products
WHERE category = 'Книги' OR category = 'Игрушки';

Essa consulta mostra os itens que pertencem à categoria “Livros” ou à categoria “Brinquedos”.

A linha passa se pelo menos uma condição for atendida:

  • o item é da categoria “Livros”;
  • o item é da categoria “Brinquedos”.

O OR é mais amplo que o AND.
Ele deixa passar mais linhas, porque basta uma das condições ser atendida.


O feixe captura itens acima de 4000 com estoque apertado — o tipo de seleção que avisava ao comprador que era hora de repor.

Análise da consulta do exemplo

Vamos olhar a consulta com mais atenção:

SELECT name, price, stock
FROM products
WHERE price > 4000 AND stock < 60
ORDER BY price DESC;

Ela faz quatro coisas:

  1. Pega as linhas da tabela products.
  2. Verifica cada linha com a condição:
price > 4000 AND stock < 60
  1. Mantém apenas as linhas em que a condição é verdadeira.
  2. Mostra as colunas name, price e stock e ordena o resultado por preço, do maior para o menor.

Em linguagem de gente, a consulta diz:

Mostre o nome, o preço e o estoque dos itens da tabela products,
mas só dos que custam mais de 4000 e têm menos de 60 unidades em estoque,
e ordene do mais caro para o mais barato.

Uma consulta assim já não parece um exercício, e sim uma ferramenta analítica de trabalho.

Ela responde a uma pergunta concreta do negócio:

Quais itens caros podem acabar em breve?

No Vault-9, linhas assim não são apenas números.
São sinais.
Lá em 2024, um comprador olhava para uma saída dessas e entendia: era preciso repor o estoque antes que os clientes vissem a prateleira vazia.


Como o banco “pensa” ao executar uma consulta

Quem está começando costuma ler o SQL de cima para baixo e achar que o banco executa o SELECT primeiro.

Mas, logicamente, a consulta funciona de outro jeito.

Para a consulta:

SELECT name, price
FROM products
WHERE price > 4000
ORDER BY price DESC;

a ordem lógica aproximada é esta:

  1. FROM products
    O banco entende de qual tabela vêm as linhas.

  2. WHERE price > 4000
    O banco verifica cada linha e mantém só as que se encaixam.

  3. SELECT name, price
    O banco monta as colunas do resultado.

  4. ORDER BY price DESC
    O banco ordena as linhas finais.

Ou seja, o WHERE age antes de o resultado final ser montado.

É exatamente por isso que dá para filtrar linhas por uma coluna que você não mostra no SELECT:

SELECT name
FROM products
WHERE price > 4000;

O resultado vai trazer apenas name, mas o banco continua usando price na etapa de filtragem.


Exemplo da história: os pedidos que aguardam

O feixe do WHERE não ilumina só produtos e números.

Na tabela orders há pedidos com status pending — “aguardando”.

SELECT id, customer_name, status
FROM orders
WHERE status = 'pending';

Uma consulta dessas mostra apenas os pedidos que ainda esperam para ser processados.

Num sistema comum, isso é uma tarefa de rotina para um gerente: descobrir por que o pedido travou.

Mas, no arquivo da velha Terra, essas linhas soam diferente.
Alguns pedidos aguardam há quase cento e sessenta anos.
Ninguém nunca vai recebê-los.
Mas os dados ainda guardam honestamente o status:

pending

aguardando.

QUERY: pending aqui quer dizer “aguardando para sempre”. Não se demore nisso, cadete. Continue iluminando.


Precedência de AND e OR: a armadilha que fica calada

Enquanto o WHERE usa só AND ou só OR, tudo costuma ficar claro.

Por exemplo:

WHERE price > 4000 AND stock < 60

Ou:

WHERE category = 'Книги' OR category = 'Игрушки'

Mas os problemas começam quando AND e OR se misturam numa mesma condição.

Os operadores lógicos têm uma ordem de precedência:

  1. NOT
  2. AND
  3. OR

Isso quer dizer que o AND liga as condições com mais força do que o OR.

Veja esta consulta:

-- Queríamos: itens de Livros ou Brinquedos mais baratos que 1500
SELECT name, category, price
FROM products
WHERE category = 'Книги' OR category = 'Игрушки' AND price < 1500;

À primeira vista, parece que a consulta significa:

Mostre os livros ou os brinquedos que custam menos de 1500.

Mas o SGBD vai lê-la de outro jeito:

WHERE category = 'Книги'
   OR (category = 'Игрушки' AND price < 1500)

A condição de preço price < 1500 «grudou» só nos brinquedos.

No resultado vão entrar:

  • todos os livros, até os caros;
  • só os brinquedos que custam menos de 1500.

Ou seja, um livro caro também vai aparecer no resultado, mesmo que a intenção fosse selecionar apenas os itens baratos.

A consulta está sintaticamente correta.
O banco de dados não vai acusar erro.
Ele vai executar honestamente o que está escrito.

O problema é que o que está escrito não é o que se queria dizer.

É isso que chamamos de erro lógico silencioso.


Por que isso é perigoso: linha por linha

Suponha que a tabela tenha estes itens:

namecategoryprice
Algoritmos na práticaLivros1690
Drone infantilBrinquedos1200
Kit da estação orbitalBrinquedos2300
Cabo de alimentaçãoEletrônicos700

A consulta sem parênteses:

SELECT name, category, price
FROM products
WHERE category = 'Книги' OR category = 'Игрушки' AND price < 1500;

O banco vai ler assim:

WHERE category = 'Книги'
   OR (category = 'Игрушки' AND price < 1500)

Vamos conferir as linhas:

Linha 1: “Algoritmos na prática”

category = 'Книги' → TRUE

Como a primeira parte já é TRUE, a linha passa.
O preço de 1690 não atrapalha, porque a condição de preço vale só para os brinquedos.

Linha 2: “Drone infantil”

category = 'Игрушки' → TRUE
price < 1500 → TRUE

As duas partes depois do AND são verdadeiras, e a linha passa.

Linha 3: “Kit da estação orbital”

category = 'Игрушки' → TRUE
price < 1500 → FALSE

Depois do AND o resultado é FALSE, e a linha não passa.

Linha 4: “Cabo de alimentação”

category = 'Книги' → FALSE
category = 'Игрушки' → FALSE

A linha não passa.

O erro final: um livro caro entrou no resultado, embora a nossa intenção fosse trazer itens mais baratos que 1500.


Os parênteses devolvem o sentido à consulta

Se queremos selecionar itens das categorias “Livros” ou “Brinquedos”, mas todos eles precisam custar menos de 1500, é preciso agrupar as categorias explicitamente:

SELECT name, category, price
FROM products
WHERE (category = 'Книги' OR category = 'Игрушки')
  AND price < 1500;

Agora a condição se lê assim:

Primeiro verifique que o item é um livro ou um brinquedo.
Depois verifique que o preço dele é menor que 1500.

Os parênteses deixam claro, para o banco e para quem lê, como a condição deve ser entendida.

Regra de arquivista:

Sempre que AND e OR aparecerem juntos no mesmo WHERE, use parênteses.

Mesmo quando a precedência “já parece óbvia”.

O não detecta erro de lógica.
Mas quem for ler sua consulta daqui a cem anos vai agradecer.


Um erro silencioso é mais perigoso que um erro de sintaxe.

Se você escrever uma consulta com erro de sintaxe, o banco para e avisa:
“Não consigo executar isto”.

Mas, se você errar a lógica do WHERE, o banco pode executar a consulta sem reclamar nada.

Você vai receber uma tabela.
Ela vai parecer plausível.
Vai ter linhas.
Talvez até muitas linhas.

Mas não serão as linhas que você queria.

Por isso, em análise de dados e em teste de consultas, é importante verificar não só que a consulta roda, mas também que ela devolve o que você realmente queria.


Uma armadilha importante: NULL não se testa com =

O SQL tem um valor especial: NULL.

NULL não significa zero, nem string vazia, nem a palavra “não”.
NULL significa:

o valor é desconhecido ou está ausente.

Um pedido, por exemplo, pode ainda não ter data de entrega:

delivered_at = NULL

Quem está começando costuma tentar encontrar essas linhas assim:

SELECT id, status, delivered_at
FROM orders
WHERE delivered_at = NULL;

Mas essa verificação está errada.

No SQL não dá para comparar um valor com NULL usando =.
Porque NULL é justamente o desconhecido.

O jeito certo é este:

SELECT id, status, delivered_at
FROM orders
WHERE delivered_at IS NULL;

E, se você precisa das linhas em que o valor está preenchido:

SELECT id, status, delivered_at
FROM orders
WHERE delivered_at IS NOT NULL;

A ideia principal:

  • para valores comuns usamos =, <>, <, >, <=, >=;
  • para NULL usamos IS NULL e IS NOT NULL.

Ainda vamos tratar do NULL em detalhe, numa aula só dele, mas já vale guardar isto:
WHERE column = NULL é quase sempre um erro.


Detalhe profissional: só entram no resultado as linhas em que a condição do WHERE deu TRUE.

Se a condição deu FALSE, a linha não passa.
Se a condição deu por causa de um NULL, a linha também não passa.

Por isso o NULL pode influenciar a filtragem sem você perceber.


Erros comuns de quem está começando

Erro 1. Achar que o WHERE escolhe colunas

Ideia errada:

o WHERE serve para escolher os campos que você quer.

Ideia certa:

o WHERE serve para escolher as linhas que você quer.

Quem escolhe as colunas é o SELECT.

SELECT name, price
FROM products
WHERE category = 'Книги';

Aqui:

  • SELECT name, price escolhe as colunas;
  • WHERE category = 'Книги' escolhe as linhas.

Erro 2. Escrever == no lugar de =

Errado:

WHERE status == 'paid'

Certo:

WHERE status = 'paid'

Erro 3. Esquecer as aspas em volta do texto

Errado:

WHERE status = paid

Certo:

WHERE status = 'paid'

Erro 4. Misturar AND e OR sem parênteses

Perigoso:

WHERE status = 'pending' OR status = 'paid' AND total > 5000;

Melhor:

WHERE (status = 'pending' OR status = 'paid')
  AND total > 5000;

Erro 5. Testar NULL com =

Errado:

WHERE delivered_at = NULL

Certo:

WHERE delivered_at IS NULL

Erro 6. Colocar o WHERE depois do ORDER BY

Errado:

SELECT name, price
FROM products
ORDER BY price DESC
WHERE price > 4000;

Certo:

SELECT name, price
FROM products
WHERE price > 4000
ORDER BY price DESC;

Numa consulta comum, o WHERE vem depois do FROM, mas antes do ORDER BY.


Interview question

Pergunta de entrevista:
o que esta condição retorna?

WHERE a = 1 OR b = 2 AND c = 3

Resposta forte:
o AND liga com mais força que o OR, então a condição é lida assim:

WHERE a = 1 OR (b = 2 AND c = 3)

Ou seja, vão entrar no resultado:

  • todas as linhas em que a = 1;
  • mais as linhas em que valem ao mesmo tempo b = 2 e c = 3.

Se a intenção era outro agrupamento, os parênteses são necessários.

Na prática, em condições mistas vale sempre usar parênteses.
É uma defesa simples contra erros lógicos silenciosos.


Check yourself
O que o WHERE faz?
Check yourself
Qual operador o SQL usa para “diferente de”?
Check yourself
Como o SGBD vai ler esta condição?
WHERE category = 'Книги' OR category = 'Игрушки' AND price < 1500
Practice: solve the tasks
Solved 0 of 3 · any 2 is enough to pass