BETWEEN, IN e LIKE: filtros especiais

1. Introdução aos Filtros Especiais

Filtros especiais são operadores SQL que ampliam a capacidade de filtragem da cláusula WHERE para além das comparações básicas (=, >, <). Enquanto filtros básicos comparam valores individuais, os especiais permitem trabalhar com intervalos, listas e padrões de texto.

Os três operadores que exploraremos neste artigo — BETWEEN, IN e LIKE — resolvem problemas comuns de forma mais elegante e eficiente que suas alternativas manuais. Compreendê-los é essencial para escrever consultas SQL produtivas e legíveis.

2. BETWEEN: Filtrando por Intervalos

O operador BETWEEN define um intervalo inclusivo de valores. Sua sintaxe é direta:

SELECT * FROM tabela
WHERE coluna BETWEEN valor_inicial AND valor_final;

Exemplo com números:

-- Funcionários com salário entre R$ 5.000 e R$ 10.000
SELECT nome, salario FROM funcionarios
WHERE salario BETWEEN 5000 AND 10000;

Exemplo com datas:

-- Pedidos realizados em janeiro de 2024
SELECT * FROM pedidos
WHERE data_pedido BETWEEN '2024-01-01' AND '2024-01-31';

Exemplo com texto:

-- Produtos cujo nome está entre 'A' e 'M' (alfabeticamente)
SELECT nome FROM produtos
WHERE nome BETWEEN 'A' AND 'M';

Cuidado importante: BETWEEN é inclusivo nos dois limites. A consulta acima com datas inclui pedidos de '2024-01-31 00:00:00', mas exclui pedidos feitos após esse horário. Para incluir o dia inteiro, use:

-- Alternativa segura para datas com timestamp
SELECT * FROM pedidos
WHERE data_pedido >= '2024-01-01' AND data_pedido < '2024-02-01';

3. IN: Filtrando por Múltiplos Valores Específicos

O operador IN verifica se um valor pertence a uma lista de valores especificados. Substitui múltiplas condições OR com muito mais clareza.

Sintaxe básica:

SELECT * FROM tabela
WHERE coluna IN (valor1, valor2, valor3);

Exemplo com números:

-- Clientes das regiões 1, 3 e 5
SELECT nome, regiao FROM clientes
WHERE regiao IN (1, 3, 5);

Exemplo com strings:

-- Pedidos com status específicos
SELECT * FROM pedidos
WHERE status IN ('PENDENTE', 'EM_TRANSITO', 'ENTREGUE');

Vantagem sobre ORs:

-- Versão com OR (menos legível)
SELECT * FROM produtos
WHERE categoria = 'ELETRÔNICOS' OR categoria = 'INFORMÁTICA' OR categoria = 'GAMES';

-- Versão com IN (mais clara e performática)
SELECT * FROM produtos
WHERE categoria IN ('ELETRÔNICOS', 'INFORMÁTICA', 'GAMES');

IN com subconsultas:

-- Clientes que já fizeram pedidos
SELECT nome FROM clientes
WHERE id IN (SELECT DISTINCT cliente_id FROM pedidos);

4. LIKE: Correspondência de Padrões em Texto

O operador LIKE permite buscas por padrões em strings usando dois caracteres curinga:

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

Busca por prefixo:

-- Produtos que começam com 'Smart'
SELECT * FROM produtos
WHERE nome LIKE 'Smart%';
-- Resultados: 'Smartphone', 'Smartwatch', 'Smart TV'

Busca por sufixo:

-- E-mails com domínio .com.br
SELECT email FROM usuarios
WHERE email LIKE '%.com.br';

Busca por padrão interno:

-- Nomes que contêm 'silva' em qualquer posição
SELECT nome FROM clientes
WHERE nome LIKE '%silva%';

Usando _ para posição exata:

-- CEPs com 8 dígitos onde o 5º é '0'
SELECT cep FROM enderecos
WHERE cep LIKE '____0___';

Diferença entre LIKE e =:

-- Busca exata (só encontra 'Maria')
SELECT * FROM clientes WHERE nome = 'Maria';

-- Busca aproximada (encontra 'Maria', 'Mariana', 'Maria José')
SELECT * FROM clientes WHERE nome LIKE 'Maria%';

5. Combinação de BETWEEN, IN e LIKE com Outros Filtros

Estes operadores podem ser combinados entre si e com outros filtros usando AND, OR e parênteses.

BETWEEN + AND + IN:

-- Pedidos caros de categorias específicas no último trimestre
SELECT * FROM pedidos
WHERE valor_total BETWEEN 1000 AND 5000
  AND categoria IN ('ELETRÔNICOS', 'INFORMÁTICA')
  AND data_pedido BETWEEN '2024-01-01' AND '2024-03-31';

LIKE combinado com operadores lógicos:

-- Clientes com nome começando com 'A' ou 'B', e e-mail corporativo
SELECT * FROM clientes
WHERE (nome LIKE 'A%' OR nome LIKE 'B%')
  AND email LIKE '%@empresa.com';

Ordem de precedência e parênteses:

-- Sem parênteses: interpretação incorreta (OR tem menor precedência)
SELECT * FROM produtos
WHERE preco BETWEEN 100 AND 500
   OR categoria = 'PROMOÇÃO' AND estoque > 0;

-- Com parênteses: lógica correta
SELECT * FROM produtos
WHERE (preco BETWEEN 100 AND 500
   OR categoria = 'PROMOÇÃO')
  AND estoque > 0;

6. Performance e Boas Práticas

Quando BETWEEN é vantajoso:

  • Para intervalos contíguos, BETWEEN é mais legível e igualmente eficiente que >= AND <=.
  • Em índices, o otimizador trata BETWEEN como duas comparações, sem perda de performance.

Cuidados com LIKE e índices:

-- Usa índice (busca por prefixo) → eficiente
SELECT * FROM clientes WHERE nome LIKE 'Silva%';

-- Ignora índice (coringa no início) → full scan
SELECT * FROM clientes WHERE nome LIKE '%Silva%';

Para buscas com % no início, considere índices全文搜索 (full-text search) ou expressões regulares.

Alternativas ao LIKE:

-- ILIKE: case-insensitive (PostgreSQL)
SELECT * FROM clientes WHERE nome ILIKE 'maria%';

-- SIMILAR TO: expressões regulares simplificadas (SQL padrão)
SELECT * FROM clientes WHERE nome SIMILAR TO '(Sr|Sra).%';

-- Expressões regulares completas (PostgreSQL, MySQL 8+)
SELECT * FROM clientes WHERE nome ~ '^[A-Z].*silva$';

7. Exemplos Práticos e Casos de Erro Comum

Exemplo completo: relatório de pedidos

-- Pedidos de janeiro/2024, com valor entre R$ 200 e R$ 2000,
-- status 'ENTREGUE' ou 'EM_TRANSITO',
-- e cliente com nome contendo 'Santos'
SELECT p.id, p.data_pedido, p.valor_total, c.nome AS cliente
FROM pedidos p
JOIN clientes c ON p.cliente_id = c.id
WHERE p.data_pedido BETWEEN '2024-01-01' AND '2024-01-31'
  AND p.valor_total BETWEEN 200 AND 2000
  AND p.status IN ('ENTREGUE', 'EM_TRANSITO')
  AND c.nome LIKE '%Santos%'
ORDER BY p.valor_total DESC;

Erros comuns e como evitá-los:

  1. BETWEEN com datas sem timezone:
    ```text
    -- Erro: exclui pedidos das 00:00:01 às 23:59:59 do último dia
    WHERE data BETWEEN '2024-01-01' AND '2024-01-31'

-- Correto: converte para date ou usa intervalo aberto
WHERE CAST(data AS DATE) BETWEEN '2024-01-01' AND '2024-01-31'
```

  1. IN com lista vazia:
    ```text
    -- Erro: retorna 0 linhas, mas pode causar confusão em consultas dinâmicas
    WHERE status IN ()

-- Correto: validar antes ou usar condicional
WHERE (1=0) -- ou ignorar o filtro se lista vazia
```

  1. LIKE com escape de caracteres especiais:
    ```text
    -- Buscar produtos com '100%' no nome
    -- Erro: % é interpretado como coringa
    WHERE nome LIKE '%100%%'

-- Correto: usar ESCAPE
WHERE nome LIKE '%100\%%' ESCAPE '\'
```

Dicas de depuração:
- Teste filtros individualmente antes de combiná-los
- Use EXPLAIN ANALYZE para verificar se índices estão sendo usados
- Em bancos grandes, prefira LIKE 'prefixo%' a LIKE '%padrão%'

Referências