SQL OR

A Loja Aurora vai abrir uma filial no Nordeste e quer mandar um convite para os clientes de Pernambuco e para os do Ceará. Na aula AND, você viu que pedir "estado PE e estado CE" com AND não traz ninguém: nenhum cliente mora nos dois estados ao mesmo tempo. O que a Ana quer é juntar as duas listas, e para isso existe o OR (em inglês, "ou"): a linha entra se esta condição ou aquela for verdadeira. Nesta aula você também vai ver o que acontece quando AND e OR aparecem juntos, e por que os parênteses salvam a sua consulta.

Você vai aprender
  • A aceitar uma condição ou outra com OR.
  • A tabela-verdade do OR: basta uma parte ser verdadeira.
  • A usar o OR com várias alternativas na mesma coluna e com colunas diferentes.
  • Que cada OR a mais deixa o resultado maior (ou igual), nunca menor.
  • A precedência: o AND é resolvido antes do OR, e os parênteses mudam isso.
  • Os erros mais comuns: o OR pela metade, o || de outras linguagens e os parênteses sem par.

A ideia: juntar duas listas

Volte ao porteiro da aula AND. Agora a regra do evento é outra: "entra quem tem convite ou quem é VIP". Para cada pessoa da fila, ele confere:

  • Tem convite e é VIP? Entra.
  • Tem convite, mas não é VIP? Entra.
  • Não tem convite, mas é VIP? Entra.
  • Nem uma coisa nem outra? Fica de fora.

Basta uma regra valer para a pessoa entrar. Esse é o OR: a linha entra no resultado se pelo menos uma das condições for verdadeira.

A tabela-verdade

Condição ACondição BA OR BNo evento
verdadeira (1)verdadeira (1)verdadeira (1)Convite e VIP: entra
verdadeira (1)falsa (0)verdadeira (1)Só convite: entra
falsa (0)verdadeira (1)verdadeira (1)Só VIP: entra
falsa (0)falsa (0)falsa (0)Nenhuma das duas: fora

É o contrário do AND: lá, só uma combinação dava 1; aqui, só uma dá 0. Confira no banco:

SELECT 1 OR 1, 1 OR 0, 0 OR 1, 0 OR 0;
O "ou" do SQL aceita os dois

Em português, "ou" às vezes quer dizer "um ou outro, mas não os dois" ("vai de ônibus ou de carro?"). O OR do SQL não é assim: se as duas condições forem verdadeiras, a linha também entra (a primeira linha da tabela). E entra uma vez só, nunca repetida.


1. O primeiro OR

O convite da filial nova:

SELECT nome, estado
FROM clientes
WHERE estado = 'PE' OR estado = 'CE';
WHERE
"Onde": as condições começam aqui.
estado = 'PE'
A primeira condição: o cliente é de Pernambuco.
OR
"Ou": a linha passa se a primeira condição for verdadeira, se a segunda for, ou se as duas forem.
estado = 'CE'
A segunda condição: o cliente é do Ceará. Repare que a coluna é escrita de novo: cada lado do OR é uma condição completa.

Vieram 9 clientes: os 2 de Pernambuco e os 7 do Ceará, misturados na ordem da tabela. O OR juntou as duas listas numa só.

Como o banco decide, linha por linha

  1. Cliente 1, José Ribamar Silva: estado 'PI'. 'PI' = 'PE'? 0. 'PI' = 'CE'? 0. 0 OR 0 = 0: fica de fora.
  2. Cliente 4, Carlos Eduardo Lima: estado 'CE'. A primeira dá 0, a segunda dá 1. 0 OR 1 = 1: entra.
  3. Cliente 10, Juliana Paes Barbosa: estado 'PE'. A primeira dá 1. 1 OR 0 = 1: entra.
  4. …e assim com todos os 30.

2. Várias alternativas na mesma coluna

Na aula SELECT DISTINCT, você viu que a loja tem os cargos Vendedor e Vendedora, escritos de jeitos diferentes. Para ver toda a equipe de vendas, aceite os dois:

SELECT nome, cargo
FROM funcionarios
WHERE cargo = 'Vendedor' OR cargo = 'Vendedora';

Os 5 da equipe de vendas: 3 vendedores e 2 vendedoras. Dá para encadear quantos OR quiser. Os clientes das cidades menores da lista, Recife, Picos e Oeiras:

SELECT nome, cidade
FROM clientes
WHERE cidade = 'Recife' OR cidade = 'Picos' OR cidade = 'Oeiras';

Quatro clientes: dois de Recife, um de Picos, um de Oeiras. Quando a lista de alternativas cresce, escrever cidade = toda hora cansa. Para isso existe o IN, que você vai ver na aula IN: WHERE cidade IN ('Recife', 'Picos', 'Oeiras').

Missão: a loja vai fazer uma ação de vendas em São Paulo e também quer incluir todos os clientes VIP, de onde forem. Mostre os clientes que são de 'SP' ou que são VIP (vip = 1).

SELECT nome, estado, vip
FROM clientes
WHERE estado = 'SP';
SELECT nome, estado, vip
FROM clientes
WHERE estado = 'SP' OR vip = 1;

São 7 clientes de São Paulo e 5 VIPs, mas vieram 11, e não 12. A Ana Beatriz Sousa é de São Paulo e é VIP: passou nas duas condições e aparece uma vez só.


3. Condições em colunas diferentes

Como no AND, cada lado do OR pode testar uma coluna diferente. A Ana vai revisar os produtos que precisam de atenção: os muito caros (mais de R$ 200) ou os com estoque muito baixo (menos de 15):

SELECT nome, preco, estoque
FROM produtos
WHERE preco > 200 OR estoque < 15;

Três produtos. O Jogo de Panelas passa nas duas condições (249.9 e 12 unidades) e aparece uma vez. O pen drive e o carrinho de fricção passam só na segunda (estoque 0).

O que fica de fora de uma faixa

Com AND, você montou uma faixa ("entre 20 e 30"). Com OR, dá para pegar o que está fora dela, nas duas pontas. Os funcionários que ganham menos de 3000 ou mais de 5000:

SELECT nome, salario
FROM funcionarios
WHERE salario < 3000 OR salario > 5000;

Os dois salários mais altos (a gerente e a supervisora) e os dois mais baixos. Repare: aqui a mesma coluna aparece nos dois lados, e não é impossível como no AND, porque cada salário só precisa cumprir uma das condições.

Cada OR só põe, nunca tira

Acrescentar um OR é abrir mais uma porta: o resultado pode ganhar linhas ou continuar igual, mas nunca fica menor. É o contrário do AND, que só tira. Na dúvida sobre qual usar, pergunte: "eu quero restringir a lista (só quem cumpre tudo) ou ampliar (quem cumpre qualquer uma)?". Restringir é AND; ampliar é OR.


4. AND e OR juntos: a precedência

Esta é a parte mais importante da aula. A Ana quer os clientes VIP do Piauí ou do Ceará. Ela escreveu a frase do jeito que pensou:

SELECT nome, estado, vip
FROM clientes
WHERE estado = 'PI' OR estado = 'CE' AND vip = 1;

Vieram 16 clientes, e vários deles têm vip = 0! Não deu erro, mas a resposta está errada. O que aconteceu?

O AND é resolvido primeiro

Lembra da matemática da escola? Em 1 + 2 * 3, a multiplicação é feita antes da soma: o resultado é 7, e não 9. Para fazer a soma primeiro, você põe parênteses: (1 + 2) * 3 dá 9.

SELECT 1 + 2 * 3, (1 + 2) * 3;

Com AND e OR acontece o mesmo: o AND tem precedência (é resolvido antes), como a multiplicação; o OR fica para depois, como a soma. Veja com 1 e 0:

SELECT 1 OR 1 AND 0, (1 OR 1) AND 0;

Sem parênteses, o banco fez 1 AND 0 primeiro (deu 0) e depois 1 OR 0 (deu 1). Com parênteses, fez 1 OR 1 primeiro (deu 1) e depois 1 AND 0 (deu 0). Os mesmos números, as mesmas palavras, resultados diferentes.

O que o banco entendeu na consulta da Ana

Como o AND vem primeiro, o banco leu a condição da Ana assim:

estado = 'PI'   OR   (estado = 'CE' AND vip = 1)

Ou seja: "todos os clientes do Piauí, VIP ou não, e mais os clientes VIP do Ceará". Foram os 14 do Piauí mais 2 VIPs do Ceará: 16. Para dizer o que a Ana queria, os parênteses têm de juntar os dois estados:

SELECT nome, estado, vip
FROM clientes
WHERE (estado = 'PI' OR estado = 'CE') AND vip = 1;
(
Abre o grupo: o que está aqui dentro é resolvido primeiro.
estado = 'PI' OR estado = 'CE'
"Do Piauí ou do Ceará". Dá 1 para os 21 clientes desses dois estados (14 do Piauí e 7 do Ceará).
)
Fecha o grupo. Todo parêntese aberto precisa ser fechado.
AND vip = 1
E, desses, só os VIP.

Agora sim: 4 clientes, todos VIP, todos do Piauí ou do Ceará.

ConsultaO banco entendeLinhas
estado = 'PI' OR estado = 'CE' AND vip = 1Todos do PI, mais os VIPs do CE16
(estado = 'PI' OR estado = 'CE') AND vip = 1Os VIPs do PI e do CE4
A regra de ouro

Misturou AND e OR no mesmo WHERE? Use parênteses. Mesmo quando a ordem natural já daria o resultado certo, os parênteses deixam claro o que você quis dizer, para o banco e para quem ler a consulta depois. Esse erro não dá mensagem nenhuma; ele só aparece como um resultado errado, que pode passar despercebido.

Mais um exemplo, com a ordem trocada. A Ana quer os VIPs de São Paulo ou de Pernambuco:

SELECT nome, estado, vip
FROM clientes
WHERE vip = 1 AND estado = 'SP' OR estado = 'PE';

O banco leu (vip = 1 AND estado = 'SP') OR estado = 'PE': a VIP de São Paulo e todos os de Pernambuco, que não são VIP. Com parênteses:

SELECT nome, estado, vip
FROM clientes
WHERE vip = 1 AND (estado = 'SP' OR estado = 'PE');

Só a Ana Beatriz: Pernambuco não tem nenhum cliente VIP.

Missão: a Ana quer os brinquedos (categoria 5) ou artigos de esporte (categoria 6) que custem menos de R$ 20. A consulta trouxe brinquedos caros, como o jogo de tabuleiro de 79.99. Use parênteses para consertar.

SELECT nome, categoria_id, preco
FROM produtos
WHERE categoria_id = 5 OR categoria_id = 6 AND preco < 20;
SELECT nome, categoria_id, preco
FROM produtos
WHERE (categoria_id = 5 OR categoria_id = 6) AND preco < 20;

Formas diferentes de fazer a mesma coisa

Para várias alternativas na mesma coluna, o IN faz o mesmo que uma fila de OR. As duas consultas abaixo trazem os mesmos 9 clientes:

SELECT nome, estado FROM clientes WHERE estado = 'PE' OR estado = 'CE';
SELECT nome, estado FROM clientes WHERE estado IN ('PE', 'CE');

A ordem dos lados do OR não importa: estado = 'CE' OR estado = 'PE' dá o mesmo resultado. E quando a consulta tem muitas condições, o costume é pôr cada uma numa linha, com o OR e o AND no começo:

SELECT nome, estado, vip
FROM clientes
WHERE (estado = 'PI'
       OR estado = 'CE')
  AND vip = 1;
FormaQuando usar
a OR bDuas ou três alternativas, principalmente em colunas diferentes
coluna IN (…)Muitas alternativas na mesma coluna (aula IN)
(a OR b) AND cSempre que AND e OR aparecem juntos
Uma condição por linhaConsultas com muitas condições

Quando dá errado

O OR pela metade

Em português dizemos "do Piauí ou do Ceará", sem repetir "estado". A Ana escreveu igual:

SELECT nome, estado
FROM clientes
WHERE estado = 'PI' OR 'CE';

Nenhum erro, mas vieram só os 14 do Piauí. Os do Ceará sumiram. O lado direito do OR ficou sendo só o texto 'CE', e não estado = 'CE'. Quando o SQLite usa um valor sozinho como condição, ele o transforma em número: 'CE' não é um número, vira 0, e 0 é falso. Então a condição é, na prática, estado = 'PI' OR 0.

Como consertar: cada lado do OR é uma condição completa: estado = 'PI' OR estado = 'CE'.

|| no lugar de OR

Em muitas linguagens de programação, o "ou" se escreve ||. No SQLite, ele quer dizer outra coisa:

SELECT nome, estado
FROM clientes
WHERE estado = 'PI' || estado = 'CE';

Nenhuma linha, e nenhum erro. No SQL padrão, || é o operador que junta textos: 'PI' || 'CE' dá 'PICE' (ele aparece na aula Funções de Texto). O banco juntou pedaços da condição como se fossem textos e comparou o resultado com 'CE', e nenhuma linha passou. Como consertar: escreva a palavra OR.

Nos outros bancos

No MySQL, o || é um "ou", como nas linguagens de programação, e não junta textos (a não ser com o modo PIPES_AS_CONCAT ligado). A documentação dele avisa que esse || como "ou" é uma extensão fora do padrão, está obsoleta e pode sumir numa versão futura. Ou seja: a mesma consulta com || faz uma coisa no MySQL e outra no SQLite. Com a palavra OR, ela faz a mesma coisa em todos.

Parêntese aberto e não fechado
SELECT nome
FROM clientes
WHERE (estado = 'PI' OR estado = 'CE' AND vip = 1;

near ";": syntax error. O comando acabou com um parêntese ainda aberto: o banco esperava o ) e encontrou o ;. Como consertar: feche o parêntese no lugar certo: (estado = 'PI' OR estado = 'CE') AND vip = 1.

Parêntese fechado sem ter aberto
SELECT nome
FROM clientes
WHERE estado = 'PI' OR estado = 'CE') AND vip = 1;

near ")": syntax error. Agora sobrou um ) sem par. Como consertar: conte os parênteses: cada ( precisa do seu ). Os editores de código costumam destacar o par de cada parêntese, o que ajuda muito.

Esqueceu o sinal de igual
SELECT nome
FROM clientes
WHERE estado = 'PI' OR estado 'CE';

near "'CE'": syntax error. Depois de estado, o banco esperava um sinal de comparação. Como consertar: OR estado = 'CE'.

Missão: a Ana quer os clientes de Pernambuco e os do Ceará (as duas listas juntas), mas a consulta só trouxe os de Pernambuco. Conserte.

SELECT nome, estado
FROM clientes
WHERE estado = 'PE' OR 'CE';
SELECT nome, estado
FROM clientes
WHERE estado = 'PE' OR estado = 'CE';

Referência rápida

EscritaO que faz
WHERE a OR bAs linhas em que a, b ou as duas são verdadeiras
WHERE a OR b OR cAs linhas em que pelo menos uma é verdadeira
WHERE a OR b AND cO banco lê a OR (b AND c): o AND vem primeiro
WHERE (a OR b) AND cOs parênteses fazem o OR vir primeiro
SELECT 0 OR 1;Testa o OR sem tabela (dá 1)
Ordem em que o banco resolveComo na matemática
1º: o que está entre parênteses( )
2º: as comparações (=, <, >…)
3º: ANDcomo a multiplicação
4º: ORcomo a soma
SintomaCausa provável
Linhas a mais, que não cumprem uma das condiçõesAND e OR juntos sem parênteses
Faltou a segunda lista inteira, sem erroOR pela metade: estado = 'PI' OR 'CE'
Nenhuma linha, sem erro|| no lugar de OR
near ";": syntax errorParêntese sem fechar, ou um OR sobrando no fim
near ")": syntax errorParêntese fechado sem ter aberto

Exercícios

1. Recife ou Fortaleza

Complete para mostrar os clientes de Recife e os de Fortaleza:

SELECT nome FROM clientes WHERE cidade = 'Recife' cidade = 'Fortaleza';

2. Os parênteses

Complete com os parênteses para mostrar os VIPs de São Paulo ou de Fortaleza:

SELECT nome FROM clientes WHERE cidade = 'São Paulo' OR cidade = 'Fortaleza' AND vip = 1;

3. Qual é o resultado de SELECT 0 OR 0;?

4. Como o banco lê WHERE a OR b AND c?

5. A Ana escreveu WHERE cargo = 'Vendedor' OR 'Vendedora'. O que vem?

6. Uma consulta com WHERE estado = 'PE' trouxe 2 linhas. Se você acrescentar OR estado = 'CE', quantas linhas podem vir?

Missão final: os jovens do Nordeste

Missão: a loja quer os clientes de Fortaleza ou Recife nascidos a partir de 1990 (data de nascimento >= '1990-01-01'). A consulta abaixo trouxe clientes nascidos em 1969 e 1979. Descubra por quê e conserte.

SELECT nome, cidade, nascimento
FROM clientes
WHERE cidade = 'Fortaleza' OR cidade = 'Recife' AND nascimento >= '1990-01-01';
SELECT nome, cidade, nascimento
FROM clientes
WHERE (cidade = 'Fortaleza' OR cidade = 'Recife') AND nascimento >= '1990-01-01';

Sem parênteses, o banco leu "todos de Fortaleza, mais os de Recife nascidos a partir de 1990". Com os parênteses, vêm só os 4 certos: Fernanda, Juliana, Débora e Mirela.


Resumo

  • OR ("ou") junta condições no WHERE: a linha entra se pelo menos uma for verdadeira. Se as duas forem, ela entra uma vez só.
  • Na tabela-verdade, só 0 OR 0 dá 0; qualquer 1 deixa o resultado em 1.
  • Cada OR a mais só acrescenta linhas. Restringir é AND; ampliar é OR.
  • Cada lado do OR é uma condição completa: estado = 'PI' OR estado = 'CE', nunca estado = 'PI' OR 'CE'.
  • O AND é resolvido antes do OR, como a multiplicação antes da soma. Misturou os dois? Use parênteses.
  • Escreva OR, nunca ||: no SQLite, || junta textos.
  • Muitas alternativas na mesma coluna ficam mais curtas com IN.