WHERE: filtrando resultados

1. Introdução à cláusula WHERE

A cláusula WHERE é um dos pilares fundamentais do SQL. Ela permite que você filtre registros de uma tabela com base em condições específicas, retornando apenas os dados que atendem aos critérios definidos. Sem o WHERE, um SELECT retornaria todas as linhas da tabela — algo raramente desejado em aplicações reais.

A sintaxe básica é:

SELECT coluna1, coluna2, ...
FROM nome_da_tabela
WHERE condição;

Um ponto crucial para entender o comportamento do WHERE é a ordem de execução lógica das cláusulas no SQL:

  1. FROM — a tabela é selecionada
  2. WHERE — os filtros são aplicados, descartando linhas que não atendem à condição
  3. SELECT — as colunas especificadas são projetadas

Isso significa que o WHERE opera sobre todas as linhas da tabela antes da projeção final. Essa ordem tem implicações diretas no desempenho, como veremos adiante.

Vamos considerar uma tabela funcionarios com os seguintes dados:

id nome cargo salario data_contratacao ativo
1 Ana Analista 5000 2022-03-15 true
2 Bruno Gerente 8500 2020-07-01 true
3 Carla Analista 4800 2023-01-10 false
4 Daniel Diretor 12000 2019-11-20 true
5 Elisa Estagiária 2000 2024-02-01 true
SELECT nome, salario
FROM funcionarios
WHERE ativo = true;

Resultado: Ana, Bruno, Daniel, Elisa.

2. Filtros com operadores de comparação

Os operadores de comparação são a forma mais direta de filtrar dados. Os principais são:

Operador Significado
= Igual a
<> ou != Diferente de
> Maior que
< Menor que
>= Maior ou igual
<= Menor ou igual

Exemplo com números:

SELECT nome, salario
FROM funcionarios
WHERE salario >= 5000;

Resultado: Ana (5000), Bruno (8500), Daniel (12000).

Exemplo com datas:

SELECT nome, data_contratacao
FROM funcionarios
WHERE data_contratacao < '2022-01-01';

Resultado: Bruno (2020-07-01), Daniel (2019-11-20).

Exemplo com textos:

SELECT nome, cargo
FROM funcionarios
WHERE cargo = 'Analista';

Resultado: Ana, Carla.

Cuidados importantes:
- Compare tipos compatíveis. Comparar texto com número pode gerar conversões implícitas que prejudicam a performance e a precisão.
- Em bancos como MySQL, a comparação de strings pode ser case-insensitive dependendo do collation configurado. No PostgreSQL e SQL Server, por padrão, é case-sensitive.

3. Operadores lógicos: AND, OR e NOT

Para criar filtros mais complexos, combinamos condições com operadores lógicos.

AND — todas as condições devem ser verdadeiras:

SELECT nome, cargo, salario
FROM funcionarios
WHERE cargo = 'Analista' AND salario > 4500;

Resultado: Ana (5000), Carla (4800).

OR — pelo menos uma condição deve ser verdadeira:

SELECT nome, cargo, salario
FROM funcionarios
WHERE cargo = 'Gerente' OR cargo = 'Diretor';

Resultado: Bruno, Daniel.

NOT — inverte o resultado da condição:

SELECT nome, ativo
FROM funcionarios
WHERE NOT ativo;

Resultado: Carla (false).

Precedência e parênteses:

O operador AND tem precedência sobre OR. Para evitar ambiguidades, use parênteses:

SELECT nome, cargo, salario
FROM funcionarios
WHERE (cargo = 'Analista' OR cargo = 'Gerente') AND salario > 4900;

Resultado: Ana (5000), Bruno (8500).

Sem os parênteses, a lógica seria: cargo = 'Analista' OR (cargo = 'Gerente' AND salario > 4900), o que traria Ana e Bruno, mas também Carla (que é Analista com salário 4800).

4. Filtros especiais: BETWEEN e IN

BETWEEN — intervalo inclusivo (inclui os extremos):

SELECT nome, salario
FROM funcionarios
WHERE salario BETWEEN 4000 AND 6000;

Resultado: Ana (5000), Carla (4800).

É equivalente a: salario >= 4000 AND salario <= 6000.

IN — verifica se um valor pertence a uma lista:

SELECT nome, cargo
FROM funcionarios
WHERE cargo IN ('Analista', 'Diretor');

Resultado: Ana, Carla, Daniel.

Equivalente a: cargo = 'Analista' OR cargo = 'Diretor'.

Diferenças práticas:
- BETWEEN é mais legível para intervalos contínuos.
- IN é mais eficiente e legível para listas discretas de valores.
- BETWEEN funciona com datas: WHERE data_contratacao BETWEEN '2022-01-01' AND '2023-12-31' retorna Ana e Carla.

5. Filtros com LIKE e curingas

O operador LIKE permite buscar padrões em strings usando curingas:

  • % — corresponde a qualquer sequência de caracteres (inclusive vazia)
  • _ — corresponde a exatamente um caractere

Exemplos:

-- Nomes que começam com 'A'
SELECT nome FROM funcionarios WHERE nome LIKE 'A%';
-- Resultado: Ana

-- Nomes que terminam com 'a'
SELECT nome FROM funcionarios WHERE nome LIKE '%a';
-- Resultado: Ana, Carla, Elisa

-- Nomes que contêm 'an' em qualquer posição
SELECT nome FROM funcionarios WHERE nome LIKE '%an%';
-- Resultado: Ana, Daniel

-- Nomes com exatamente 5 caracteres
SELECT nome FROM funcionarios WHERE nome LIKE '_____';
-- Resultado: Bruno, Carla, Daniel, Elisa (Ana tem 3 letras)

Atenção: LIKE pode ser lento em tabelas grandes porque geralmente impede o uso de índices, especialmente quando o curinga % está no início do padrão.

6. Tratamento de valores nulos (NULL)

NULL representa ausência de valor, não é zero nem string vazia. Comparações com NULL usando = ou <> sempre retornam falso (ou desconhecido, dependendo da lógica de três valores do SQL).

Vamos adicionar um funcionário com dados incompletos:

id nome cargo salario data_contratacao ativo
6 Fábio NULL NULL 2024-06-01 true

Uso correto:

SELECT nome FROM funcionarios WHERE cargo IS NULL;
-- Resultado: Fábio

SELECT nome FROM funcionarios WHERE cargo IS NOT NULL;
-- Resultado: Ana, Bruno, Carla, Daniel, Elisa

Armadilha comum — isso NÃO funciona:

SELECT nome FROM funcionarios WHERE cargo = NULL;
-- Não retorna nenhuma linha, mesmo que existam NULLs

Outra armadilha: expressões com NULL geralmente resultam em NULL. salario + 1000 onde salario é NULL resulta em NULL.

7. Boas práticas e desempenho

Evite funções em colunas no WHERE:

-- Ruim (impede uso de índice)
SELECT nome FROM funcionarios WHERE YEAR(data_contratacao) = 2022;

-- Bom (permite uso de índice)
SELECT nome FROM funcionarios WHERE data_contratacao >= '2022-01-01' AND data_contratacao < '2023-01-01';

Filtros seletivos primeiro: coloque as condições que eliminam mais linhas no início da cláusula WHERE. Embora o otimizador do banco possa reorganizar, isso ajuda na legibilidade e pode auxiliar em bancos menos sofisticados.

Prefira IN em vez de múltiplos OR:

-- Prefira
WHERE cargo IN ('Analista', 'Gerente', 'Diretor');

-- Em vez de
WHERE cargo = 'Analista' OR cargo = 'Gerente' OR cargo = 'Diretor';

Evite lógica redundante:

-- Redundante
WHERE salario > 1000 AND salario > 500;

-- Correto
WHERE salario > 1000;

Use índices adequados: para filtros frequentes em colunas como cargo, data_contratacao ou ativo, crie índices. O banco os utilizará automaticamente quando o filtro for seletivo o suficiente.

Conclusão

A cláusula WHERE é a ferramenta essencial para extrair precisamente os dados que você precisa. Dominar seus operadores — desde comparações simples até padrões com LIKE e tratamento de NULLs — é fundamental para escrever consultas SQL eficientes e corretas. Lembre-se sempre da ordem de execução lógica e das implicações de desempenho ao construir seus filtros.

Referências