A cláusula WHERE

Prévia grátis 7 min de leitura

O segurança na porta

Imagine uma casa noturna com mil pessoas dentro. Você não quer falar com todo mundo: quer encontrar seu amigo que está usando uma jaqueta vermelha. Ao invés de olhar cada rosto, você diz ao segurança: "Só deixe passar quem estiver de jaqueta vermelha." O segurança filtra a multidão, e só as pessoas correspondentes chegam até você.

Esse segurança é a cláusula WHERE. No curso anterior, você aprendeu SELECT e FROM: como escolher quais colunas exibir e de qual tabela ler. Mas sem WHERE, toda query retorna todas as linhas da tabela. É como pedir ao segurança para deixar todo mundo passar.

WHERE é a cláusula mais importante para aplicações reais. Quase nenhuma query em produção roda sem ela.


Como o WHERE funciona no pipeline da query

Lembre-se do pipeline de query do curso anterior: Parser → Planner → Executor. A cláusula WHERE afeta todos os três estágios:

SELECT name, email FROM users WHERE active = true;
flowchart TB
  A["Parser<br/>converte WHERE active = true em um nó de filtro na AST"] --> B["Planner<br/>verifica se existe um index em active.<br/>Sim -> Index Scan (rápido). Não -> Sequential Scan (lê cada linha)"]
  B --> C["Executor<br/>avalia a condição para cada linha.<br/>Só passam linhas onde active = true; linhas rejeitadas são descartadas"]

O executor aplica sua condição WHERE como um predicado: um teste verdadeiro/falso avaliado contra cada linha candidata. Se o predicado retorna true, a linha é incluída no result set. Se false ou NULL, a linha é excluída.

Esta é uma ideia importante: WHERE não busca dados. Ele elimina dados. Toda linha começa como candidata; WHERE decide quais candidatas sobrevivem.


Operadores de comparação

SQL oferece seis operadores de comparação que funcionam com números, strings, datas e a maioria dos outros tipos de dados:

Operador Significado Exemplo
= Igual a WHERE level = 0
!= ou <> Diferente de WHERE status != 'completed'
< Menor que WHERE position < 5
> Maior que WHERE position > 3
<= Menor ou igual WHERE level <= 1
>= Maior ou igual WHERE level >= 2

Perceba que SQL usa = para comparação, não ==. Essa é uma armadilha comum para programadores vindos de Ruby, JavaScript ou Python, onde = significa atribuição e == significa comparação. Em SQL, = sempre significa comparação: não existe operador de atribuição em uma query SELECT.


Filtrando por números

Vamos usar as tabelas deste próprio app. A tabela courses tem uma coluna level armazenada como inteiro (0 = intern, 1 = junior, 2 = mid, 3 = senior). Os títulos ficam numa coluna JSON, title, com uma chave por idioma, então title->>'en' lê o título em inglês como texto:

-- Encontrar todos os cursos nível junior
SELECT title->>'en' AS title, level
FROM courses
WHERE level = 1
ORDER BY position;

Resultado:

          title          | level
-------------------------+-------
 Raw SQL: select & from  |     1
 SQL: where & operators  |     1
 ...
(101 rows)

O equivalente em ActiveRecord:

# ActiveRecord
Catalog::Course.where(level: :junior)

# SQL gerado pelo Rails
SELECT "courses".* FROM "courses" WHERE "courses"."level" = 1

Perceba que o Rails traduz o símbolo :junior para o inteiro 1 porque Catalog::Course usa enum :level. O ActiveRecord nunca cola input cru no SQL: com prepared statements ligados, o valor 1 vai separado do texto SQL; com eles desligados (como no log de desenvolvimento deste app), o Rails coloca o valor entre aspas e escapado. Nos dois casos, uma condição em hash está protegida contra SQL injection.


Filtrando por strings

Comparações de strings usam aspas simples em SQL. Aspas duplas são reservadas para identificadores (nomes de tabelas e colunas):

-- Encontrar um usuário por email
SELECT id, name, email
FROM users
WHERE email = '[email protected]';

Em ActiveRecord:

Identity::User.where(email: '[email protected]')
# SQL: SELECT "users".* FROM "users" WHERE "users"."email" = '[email protected]'

Comparações de strings no PostgreSQL são case-sensitive por padrão. 'Alice' e 'alice' são valores diferentes. Se você precisar de comparação case-insensitive, vai aprender sobre ILIKE na Aula 3.

Erro comum: Usar aspas duplas em volta de valores de string.

-- ERRADO: aspas duplas significam nome de coluna
WHERE email = "[email protected]"
-- PostgreSQL lê como: WHERE email = (coluna chamada [email protected])
-- Erro: column "[email protected]" does not exist

-- CORRETO: aspas simples para valores de string
WHERE email = '[email protected]'

Filtrando com operadores de desigualdade

Operadores de desigualdade são essenciais para queries de faixa: encontrar registros acima, abaixo ou fora de um limite:

-- Encontrar aulas após a posição 3 em um curso
SELECT title->>'en' AS title, position
FROM lessons
WHERE course_id = 5
  AND position > 3
ORDER BY position;

Resultado:

         title             | position
---------------------------+----------
 IN, BETWEEN & Ranges      |        4
 NULL Operators             |        5
 Dates & Times              |        6
 Indexes & Sargability      |        7
(4 rows)

Equivalente em ActiveRecord:

Catalog::Lesson.where(course_id: 5).where('position > ?', 3).order(:position)
# SQL: SELECT "lessons".* FROM "lessons"
#      WHERE "lessons"."course_id" = 5 AND (position > 3)
#      ORDER BY "lessons"."position" ASC

Perceba o placeholder ?: esta é uma query parametrizada. O ActiveRecord substitui ? pelo valor 3, devidamente escapado. Nunca interpole valores diretamente em strings SQL: isso cria vulnerabilidades de SQL injection.


A cláusula WHERE e NULL

Uma regra crítica: você não pode usar = ou != para comparar com NULL. Esta query retorna zero linhas, mesmo se alguns usuários não tiverem nome:

-- ERRADO: retorna nenhuma linha
SELECT * FROM users WHERE name = NULL;

-- CORRETO: use IS NULL
SELECT * FROM users WHERE name IS NULL;

Isso acontece porque SQL usa lógica de três valores: toda comparação com NULL retorna NULL (não true, não false). E WHERE só mantém linhas onde a condição é true. Vamos explorar operadores NULL em profundidade na Aula 5.


Erros comuns

Erro: Escrever WHERE active = true para colunas booleanas achando que é a única forma.
A nuance: No PostgreSQL, WHERE active, WHERE active = true e WHERE active IS TRUE todas funcionam, mas se comportam diferente com valores NULL. WHERE active e WHERE active = true ambas excluem NULLs. WHERE active IS TRUE também exclui NULLs. Mas WHERE active IS NOT FALSE inclui NULLs. Seja explícito sobre sua intenção.

Erro: Esquecer que != não captura valores NULL.
Por que está errado: WHERE status != 'completed' NÃO retorna linhas onde status é NULL, porque NULL != 'completed' resulta em NULL, não true. Se você quer essas linhas também, use: WHERE status != 'completed' OR status IS NULL.


Resumo

Conceito Ponto Chave
Cláusula WHERE Filtra linhas avaliando um predicado: só linhas que retornam true são incluídas
Operadores de comparação =, !=/<>, <, >, <=, >=: funcionam com números, strings e datas
Valores de string Sempre use aspas simples ('texto'), nunca aspas duplas (essas são para identificadores)
Comparações com NULL = NULL nunca funciona: use IS NULL ou IS NOT NULL
ActiveRecord .where Gera cláusulas WHERE parametrizadas: previne SQL injection automaticamente
Impacto no query planner Condições WHERE determinam se o planner usa Index Scan ou Sequential Scan
Queries parametrizadas Use placeholders ? no ActiveRecord: nunca interpole input do usuário em strings SQL
Aula 1 de 7 · grátis

Continue com a aula 2

AND, OR e NOT

Combinar condições com AND, OR e NOT, por que AND vem antes de OR, e os equivalentes no ActiveRecord.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...