WHERE é um filtro de linhas. Sem ele, a sua consulta retorna todas as linhas da tabela. Com ele, apenas as linhas que você realmente quer.
Pense em uma tabela como um armário cheio de roupas. SELECT * FROM clothes significa "me dê tudo o que está aí". SELECT * FROM clothes WHERE color = 'red' significa "me dê apenas as peças vermelhas". WHERE é esse filtro.
Por que WHERE importa
As tabelas do mundo real guardam dezenas de milhares — às vezes milhões — de linhas. Retornar todas elas é:
- Lento: o banco de dados faz mais trabalho e a rede transporta mais dados.
- Inútil: você normalmente quer usuários, pedidos ou produtos específicos — não a tabela inteira.
WHERE corta o ruído do lado do banco de dados antes que os dados cheguem até você. É uma das primeiras ferramentas que todo desenvolvedor e analista de SQL aprende — sem ele você não vai longe.
Como funciona por baixo dos panos
Quando você escreve SELECT ... FROM users WHERE age > 18, o banco de dados faz algo simples:
- Lê cada linha de
users uma a uma.
- Insere o valor
age da linha na condição age > 18.
- Se a condição for
TRUE, a linha vai para o resultado. Se for FALSE, é descartada.
WHERE é apenas um teste de sim/não aplicado a cada linha.
Sintaxe básica
SELECT name, age
FROM users
WHERE age > 18;
Linha por linha:
SELECT name, age — quais colunas você quer de volta.
FROM users — de qual tabela.
WHERE age > 18 — quais linhas manter (apenas pessoas com mais de 18 anos).
O resultado é uma lista de usuários adultos, apenas com o nome e a idade (sem e-mail, telefone ou qualquer outra coisa que não pedimos).
O que você pode colocar depois de WHERE
1. Comparações
= — igual
<> ou != — diferente
>, <, >=, <= — maior que, menor que, etc.
SELECT * FROM products WHERE price > 1000;
SELECT * FROM users WHERE country = 'Russia';
SELECT * FROM orders WHERE status <> 'cancelled';
Exemplo resolvido. Dada a tabela products:
| id | name | price |
|---|
| 1 | Mug | 350 |
| 2 | Kettle | 1200 |
| 3 | Microwave | 5000 |
| 4 | Spoon | 80 |
Consulta:
SELECT name, price FROM products WHERE price > 1000;
Resultado:
| name | price |
|---|
| Kettle | 1200 |
| Microwave | 5000 |
Mug e Spoon ficaram de fora — o preço deles está abaixo de 1000.
2. Operadores lógicos AND, OR, NOT
AND — ambas as condições precisam ser verdadeiras
OR — pelo menos uma precisa ser verdadeira
NOT — nega uma condição
SELECT * FROM users
WHERE country = 'Russia' AND age >= 21;
SELECT * FROM orders
WHERE status = 'paid' OR status = 'shipped';
SELECT * FROM products
WHERE NOT in_stock;
AND versus OR, na prática. Tabela users:
| id | name | country | age |
|---|
| 1 | Anna | Russia | 25 |
| 2 | Bob | USA | 30 |
| 3 | Vera | Russia | 17 |
| 4 | Grisha | Russia | 40 |
Consulta com AND (ambas as condições):
SELECT name FROM users WHERE country = 'Russia' AND age >= 21;
Resultado:
Vera ficou de fora (17, abaixo de 21). Bob ficou de fora (não é Russia). Apenas Anna e Grisha satisfazem ambas as condições ao mesmo tempo.
A mesma consulta com OR (pelo menos uma):
SELECT name FROM users WHERE country = 'Russia' OR age >= 21;
Resultado:
Agora os quatro correspondem. Anna, Vera, Grisha — Russia. Bob — 30 (≥ 21). Cada linha tem pelo menos uma condição verdadeira. Uma diferença reveladora entre AND e OR.
3. Um conjunto de valores: IN
Quando você quer verificar se um valor é uma de várias opções:
SELECT * FROM users
WHERE country IN ('Russia', 'Belarus', 'Kazakhstan');
É a forma abreviada de:
WHERE country = 'Russia' OR country = 'Belarus' OR country = 'Kazakhstan'
IN se lê de forma mais limpa, especialmente quando a lista cresce.
Também existe NOT IN:
SELECT * FROM users WHERE country NOT IN ('USA', 'Canada');
4. Um intervalo: BETWEEN
Ótimo para datas, números — qualquer coisa ordenável.
SELECT * FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31';
SELECT * FROM products
WHERE price BETWEEN 100 AND 500;
Importante: BETWEEN inclui ambas as extremidades. BETWEEN 100 AND 500 é o mesmo que >= 100 AND <= 500. O 100 exato e o 500 exato também entram.
5. Busca de texto: LIKE
Para correspondências parciais de strings:
SELECT * FROM users WHERE email LIKE '%@gmail.com';
SELECT * FROM users WHERE name LIKE 'A%';
SELECT * FROM users WHERE name LIKE '%nn%';
Dois curingas no LIKE:
% — qualquer quantidade de caracteres (inclusive zero)
_ — exatamente um caractere
Exemplo com _: WHERE phone LIKE '+1 555___' — telefones que começam com +1 555 seguidos de três caracteres quaisquer.
6. NULL é uma coisa à parte
Esta é a armadilha mais comum para iniciantes. NULL no SQL não é um valor — é a ausência de um. "Desconhecido". "Não preenchido".
E você não pode compará-lo com =. Em lugar nenhum. Até NULL = NULL não retorna TRUE, mas sim NULL de novo ("desconhecido igual a desconhecido — quem sabe").
SELECT * FROM users WHERE deleted_at = NULL;
SELECT * FROM users WHERE deleted_at IS NULL;
SELECT * FROM users WHERE deleted_at IS NOT NULL;
Lembre-se: para NULL — apenas IS NULL e IS NOT NULL, nunca = nem <>.
Exemplo maior: antes e depois
Dada a tabela orders:
| id | user_id | amount | status | country |
|---|
| 1 | 10 | 500 | paid | Russia |
| 2 | 11 | 1500 | paid | USA |
| 3 | 12 | 200 | cancelled | Russia |
| 4 | 13 | 3000 | paid | Russia |
| 5 | 14 | 800 | pending | Russia |
| 6 | 15 | 4500 | paid | Belarus |
Objetivo: "pedidos pagos da Russia, com valor acima de 1000".
Consulta:
SELECT id, amount
FROM orders
WHERE status = 'paid'
AND country = 'Russia'
AND amount > 1000;
Resultado:
Quem ficou de fora e por quê:
- #1: pago e da Russia, mas valor 500 — não passa em
amount > 1000.
- #2: pago e grande o suficiente, mas USA — não é Russia.
- #3: cancelado — não está pago.
- #5: pendente — não está pago.
- #6: pago e grande o suficiente, mas Belarus — não é Russia.
Apenas o #4 satisfaz as três condições de uma vez (AND).
Agora troque AND por OR nos mesmos dados:
SELECT id, amount, country, status
FROM orders
WHERE status = 'paid'
OR country = 'Russia'
OR amount > 1000;
Resultado:
| id | amount | country | status |
|---|
| 1 | 500 | Russia | paid |
| 2 | 1500 | USA | paid |
| 3 | 200 | Russia | cancelled |
| 4 | 3000 | Russia | paid |
| 5 | 800 | Russia | pending |
| 6 | 4500 | Belarus | paid |
Todas as seis linhas passam. Cada linha atende a pelo menos uma das três condições. Um lembrete sólido de quão diferentes são AND e OR.
Mais um: datas e texto
A mesma tabela orders, com datas e e-mail:
Objetivo: "pedidos de 2024, apenas de usuários do gmail".
SELECT id, email, amount
FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'
AND email LIKE '%@gmail.com';
Resultado:
O pedido #2 fica de fora (yandex.ru, não gmail). O #4 fica de fora (2025, não 2024).
Erros comuns de iniciante
1. Comparar NULL com =. Nunca funciona. Use IS NULL / IS NOT NULL.
2. As aspas. Strings e datas vão entre aspas simples '...'. Números não precisam de aspas. Aspas duplas "..." no PostgreSQL servem para identificadores (nomes de coluna), não para strings.
WHERE name = 'Alice' AND age = 30
WHERE name = "Alice"
3. Confundir AND e OR. Use sempre parênteses nas condições compostas para tornar a precedência explícita:
WHERE country = 'Russia'
AND ((sex = 'M' AND age > 21) OR (sex = 'F' AND age > 18));
Sem parênteses, a lógica pode parar em um lugar completamente diferente do que você pretendia.
4. Filtrar agregações com WHERE. Não funciona. WHERE é executado antes do agrupamento e não sabe nada de COUNT, SUM, etc. Para condições sobre agregações existe o HAVING.
SELECT country, COUNT(*) FROM users
GROUP BY country
WHERE COUNT(*) > 100;
SELECT country, COUNT(*) FROM users
GROUP BY country
HAVING COUNT(*) > 100;
5. Sensibilidade a maiúsculas e minúsculas. WHERE name = 'Alice' e WHERE name = 'alice' são condições diferentes na maioria dos bancos de dados. Se as maiúsculas não devem importar, normalize os dois lados:
WHERE LOWER(name) = 'alice'
6. Esquecer o AND entre condições. Várias condições precisam de um AND ou OR explícito — aqui não há vírgula implícita.
WHERE country = 'Russia' age > 21
WHERE country = 'Russia' AND age > 21
Resumo rápido
WHERE filtra linhas em SELECT, UPDATE e DELETE.
- As condições usam comparações,
AND/OR/NOT, IN, BETWEEN, LIKE.
- Para
NULL, use IS NULL / IS NOT NULL — as comparações normais falham silenciosamente.
- Quanto mais apertado for o seu
WHERE, menos dados o banco de dados retorna — e mais rápido tudo fica.
- Use sempre parênteses nas condições compostas
AND/OR. Não adivinhe a precedência, escreva-a.
Experimente você mesmo
Três exercícios de dificuldade crescente sobre a mesma tabela orders:
- Encontre todos os pedidos pagos acima de 500.
- Encontre os pedidos de junho de 2024 de usuários fora da Russia.
- Encontre os pedidos em que
delivered_at ainda não está definido (ou seja, NULL).
Escreva primeiro as consultas por conta própria e depois confira. Se não fizerem sentido de imediato — é totalmente normal. SQL se lê da esquerda para a direita como o inglês, e vira automático com a repetição.
WHEREé um filtro de linhas. Sem ele, a sua consulta retorna todas as linhas da tabela. Com ele, apenas as linhas que você realmente quer.Pense em uma tabela como um armário cheio de roupas.
SELECT * FROM clothessignifica "me dê tudo o que está aí".SELECT * FROM clothes WHERE color = 'red'significa "me dê apenas as peças vermelhas".WHEREé esse filtro.Por que WHERE importa
As tabelas do mundo real guardam dezenas de milhares — às vezes milhões — de linhas. Retornar todas elas é:
WHEREcorta o ruído do lado do banco de dados antes que os dados cheguem até você. É uma das primeiras ferramentas que todo desenvolvedor e analista de SQL aprende — sem ele você não vai longe.Como funciona por baixo dos panos
Quando você escreve
SELECT ... FROM users WHERE age > 18, o banco de dados faz algo simples:usersuma a uma.ageda linha na condiçãoage > 18.TRUE, a linha vai para o resultado. Se forFALSE, é descartada.WHEREé apenas um teste de sim/não aplicado a cada linha.Sintaxe básica
SELECT name, age FROM users WHERE age > 18;Linha por linha:
SELECT name, age— quais colunas você quer de volta.FROM users— de qual tabela.WHERE age > 18— quais linhas manter (apenas pessoas com mais de 18 anos).O resultado é uma lista de usuários adultos, apenas com o nome e a idade (sem e-mail, telefone ou qualquer outra coisa que não pedimos).
O que você pode colocar depois de WHERE
1. Comparações
=— igual<>ou!=— diferente>,<,>=,<=— maior que, menor que, etc.SELECT * FROM products WHERE price > 1000; SELECT * FROM users WHERE country = 'Russia'; SELECT * FROM orders WHERE status <> 'cancelled';Exemplo resolvido. Dada a tabela
products:Consulta:
SELECT name, price FROM products WHERE price > 1000;Resultado:
Mug e Spoon ficaram de fora — o preço deles está abaixo de 1000.
2. Operadores lógicos AND, OR, NOT
AND— ambas as condições precisam ser verdadeirasOR— pelo menos uma precisa ser verdadeiraNOT— nega uma condiçãoSELECT * FROM users WHERE country = 'Russia' AND age >= 21; SELECT * FROM orders WHERE status = 'paid' OR status = 'shipped'; SELECT * FROM products WHERE NOT in_stock;AND versus OR, na prática. Tabela
users:Consulta com
AND(ambas as condições):SELECT name FROM users WHERE country = 'Russia' AND age >= 21;Resultado:
Vera ficou de fora (17, abaixo de 21). Bob ficou de fora (não é Russia). Apenas Anna e Grisha satisfazem ambas as condições ao mesmo tempo.
A mesma consulta com
OR(pelo menos uma):SELECT name FROM users WHERE country = 'Russia' OR age >= 21;Resultado:
Agora os quatro correspondem. Anna, Vera, Grisha — Russia. Bob — 30 (≥ 21). Cada linha tem pelo menos uma condição verdadeira. Uma diferença reveladora entre
ANDeOR.3. Um conjunto de valores: IN
Quando você quer verificar se um valor é uma de várias opções:
SELECT * FROM users WHERE country IN ('Russia', 'Belarus', 'Kazakhstan');É a forma abreviada de:
WHERE country = 'Russia' OR country = 'Belarus' OR country = 'Kazakhstan'INse lê de forma mais limpa, especialmente quando a lista cresce.Também existe
NOT IN:SELECT * FROM users WHERE country NOT IN ('USA', 'Canada');4. Um intervalo: BETWEEN
Ótimo para datas, números — qualquer coisa ordenável.
SELECT * FROM orders WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'; SELECT * FROM products WHERE price BETWEEN 100 AND 500;Importante:
BETWEENinclui ambas as extremidades.BETWEEN 100 AND 500é o mesmo que>= 100 AND <= 500. O 100 exato e o 500 exato também entram.5. Busca de texto: LIKE
Para correspondências parciais de strings:
-- Todos com um endereço do gmail SELECT * FROM users WHERE email LIKE '%@gmail.com'; -- Nomes que começam com 'A' SELECT * FROM users WHERE name LIKE 'A%'; -- Nomes que contêm 'nn' em qualquer lugar SELECT * FROM users WHERE name LIKE '%nn%';Dois curingas no
LIKE:%— qualquer quantidade de caracteres (inclusive zero)_— exatamente um caractereExemplo com
_:WHERE phone LIKE '+1 555___'— telefones que começam com +1 555 seguidos de três caracteres quaisquer.6. NULL é uma coisa à parte
Esta é a armadilha mais comum para iniciantes.
NULLno SQL não é um valor — é a ausência de um. "Desconhecido". "Não preenchido".E você não pode compará-lo com
=. Em lugar nenhum. AtéNULL = NULLnão retornaTRUE, mas simNULLde novo ("desconhecido igual a desconhecido — quem sabe").-- ERRADO: não retorna nada, mesmo que existam NULLs SELECT * FROM users WHERE deleted_at = NULL; -- CERTO SELECT * FROM users WHERE deleted_at IS NULL; SELECT * FROM users WHERE deleted_at IS NOT NULL;Lembre-se: para
NULL— apenasIS NULLeIS NOT NULL, nunca=nem<>.Exemplo maior: antes e depois
Dada a tabela
orders:Objetivo: "pedidos pagos da Russia, com valor acima de 1000".
Consulta:
SELECT id, amount FROM orders WHERE status = 'paid' AND country = 'Russia' AND amount > 1000;Resultado:
Quem ficou de fora e por quê:
amount > 1000.Apenas o #4 satisfaz as três condições de uma vez (
AND).Agora troque
ANDporORnos mesmos dados:SELECT id, amount, country, status FROM orders WHERE status = 'paid' OR country = 'Russia' OR amount > 1000;Resultado:
Todas as seis linhas passam. Cada linha atende a pelo menos uma das três condições. Um lembrete sólido de quão diferentes são
ANDeOR.Mais um: datas e texto
A mesma tabela
orders, com datas e e-mail:Objetivo: "pedidos de 2024, apenas de usuários do gmail".
SELECT id, email, amount FROM orders WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31' AND email LIKE '%@gmail.com';Resultado:
O pedido #2 fica de fora (yandex.ru, não gmail). O #4 fica de fora (2025, não 2024).
Erros comuns de iniciante
1. Comparar NULL com
=. Nunca funciona. UseIS NULL/IS NOT NULL.2. As aspas. Strings e datas vão entre aspas simples
'...'. Números não precisam de aspas. Aspas duplas"..."no PostgreSQL servem para identificadores (nomes de coluna), não para strings.-- Certo WHERE name = 'Alice' AND age = 30 -- Errado: isto procura uma coluna chamada Alice — erro WHERE name = "Alice"3. Confundir AND e OR. Use sempre parênteses nas condições compostas para tornar a precedência explícita:
-- Você quer: país Russia AND (homens com mais de 21 OR mulheres com mais de 18) WHERE country = 'Russia' AND ((sex = 'M' AND age > 21) OR (sex = 'F' AND age > 18));Sem parênteses, a lógica pode parar em um lugar completamente diferente do que você pretendia.
4. Filtrar agregações com WHERE. Não funciona.
WHEREé executado antes do agrupamento e não sabe nada deCOUNT,SUM, etc. Para condições sobre agregações existe oHAVING.-- Errado SELECT country, COUNT(*) FROM users GROUP BY country WHERE COUNT(*) > 100; -- Certo SELECT country, COUNT(*) FROM users GROUP BY country HAVING COUNT(*) > 100;5. Sensibilidade a maiúsculas e minúsculas.
WHERE name = 'Alice'eWHERE name = 'alice'são condições diferentes na maioria dos bancos de dados. Se as maiúsculas não devem importar, normalize os dois lados:WHERE LOWER(name) = 'alice'6. Esquecer o AND entre condições. Várias condições precisam de um
ANDouORexplícito — aqui não há vírgula implícita.-- Errado (sem AND) WHERE country = 'Russia' age > 21 -- Certo WHERE country = 'Russia' AND age > 21Resumo rápido
WHEREfiltra linhas emSELECT,UPDATEeDELETE.AND/OR/NOT,IN,BETWEEN,LIKE.NULL, useIS NULL/IS NOT NULL— as comparações normais falham silenciosamente.WHERE, menos dados o banco de dados retorna — e mais rápido tudo fica.AND/OR. Não adivinhe a precedência, escreva-a.Experimente você mesmo
Três exercícios de dificuldade crescente sobre a mesma tabela
orders:delivered_atainda não está definido (ou seja,NULL).Escreva primeiro as consultas por conta própria e depois confira. Se não fizerem sentido de imediato — é totalmente normal. SQL se lê da esquerda para a direita como o inglês, e vira automático com a repetição.