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.
- A aceitar uma condição ou outra com
OR. - A tabela-verdade do
OR: basta uma parte ser verdadeira. - A usar o
ORcom várias alternativas na mesma coluna e com colunas diferentes. - Que cada
ORa mais deixa o resultado maior (ou igual), nunca menor. - A precedência: o
ANDé resolvido antes doOR, e os parênteses mudam isso. - Os erros mais comuns: o
ORpela 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 A | Condição B | A OR B | No 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;
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
- Cliente 1, José Ribamar Silva: estado
'PI'.'PI' = 'PE'? 0.'PI' = 'CE'? 0.0 OR 0= 0: fica de fora. - Cliente 4, Carlos Eduardo Lima: estado
'CE'. A primeira dá 0, a segunda dá 1.0 OR 1= 1: entra. - Cliente 10, Juliana Paes Barbosa: estado
'PE'. A primeira dá 1.1 OR 0= 1: entra. - …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.
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á.
| Consulta | O banco entende | Linhas |
|---|---|---|
estado = 'PI' OR estado = 'CE' AND vip = 1 | Todos do PI, mais os VIPs do CE | 16 |
(estado = 'PI' OR estado = 'CE') AND vip = 1 | Os VIPs do PI e do CE | 4 |
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;
| Forma | Quando usar |
|---|---|
a OR b | Duas ou três alternativas, principalmente em colunas diferentes |
coluna IN (…) | Muitas alternativas na mesma coluna (aula IN) |
(a OR b) AND c | Sempre que AND e OR aparecem juntos |
| Uma condição por linha | Consultas com muitas condições |
Quando dá errado
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.
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.
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.
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.
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
| Escrita | O que faz |
|---|---|
WHERE a OR b | As linhas em que a, b ou as duas são verdadeiras |
WHERE a OR b OR c | As linhas em que pelo menos uma é verdadeira |
WHERE a OR b AND c | O banco lê a OR (b AND c): o AND vem primeiro |
WHERE (a OR b) AND c | Os parênteses fazem o OR vir primeiro |
SELECT 0 OR 1; | Testa o OR sem tabela (dá 1) |
| Ordem em que o banco resolve | Como na matemática |
|---|---|
| 1º: o que está entre parênteses | ( ) |
2º: as comparações (=, <, >…) | |
3º: AND | como a multiplicação |
4º: OR | como a soma |
| Sintoma | Causa provável |
|---|---|
| Linhas a mais, que não cumprem uma das condições | AND e OR juntos sem parênteses |
| Faltou a segunda lista inteira, sem erro | OR pela metade: estado = 'PI' OR 'CE' |
| Nenhuma linha, sem erro | || no lugar de OR |
near ";": syntax error | Parêntese sem fechar, ou um OR sobrando no fim |
near ")": syntax error | Parêntese fechado sem ter aberto |
Exercícios
1. Recife ou Fortaleza
Complete para mostrar os clientes de Recife e os de Fortaleza:
2. Os parênteses
Complete com os parênteses para mostrar os VIPs de São Paulo ou de Fortaleza:
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 noWHERE: a linha entra se pelo menos uma for verdadeira. Se as duas forem, ela entra uma vez só.- Na tabela-verdade, só
0 OR 0dá 0; qualquer 1 deixa o resultado em 1. - Cada
ORa mais só acrescenta linhas. Restringir éAND; ampliar éOR. - Cada lado do
ORé uma condição completa:estado = 'PI' OR estado = 'CE', nuncaestado = 'PI' OR 'CE'. - O
ANDé resolvido antes doOR, 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.