SQL ANY e ALL
"Este produto é mais caro que todos os da Papelaria?" "Este brinquedo é mais barato que algum livro?" São perguntas que comparam um valor com uma lista inteira. O SQL padrão tem duas palavras para isso: ALL ("todos") e ANY ("algum", também escrito SOME). Elas existem no MySQL, no PostgreSQL e no SQL Server, e você vai encontrá-las em muito código. Mas há um detalhe importante: o SQLite não tem ANY nem ALL. Nesta aula você aprende o que elas significam, vê o erro real que o SQLite dá e aprende a escrever a mesma pergunta de um jeito que funciona em todos os bancos.
- O que significa
> ALL (…)e> ANY (…), com uma comparação do dia a dia. - O erro real que o SQLite dá quando encontra
ANYouALLnuma comparação. - Os equivalentes que rodam no SQLite:
MAXeMINnuma subconsulta,IN,NOT IN,EXISTSeNOT EXISTS. - O caso traiçoeiro da lista vazia, em que
MAXeALLrespondem diferente. - Uma tabela para traduzir qualquer
ANY/ALLque você encontrar.
Esta aula usa subconsultas: se ainda não leu, veja Subconsultas e EXISTS. Os trechos com ANY/ALL marcados como ilustrativos são do MySQL, do PostgreSQL e do SQL Server e não rodam aqui; todos os outros rodam de verdade no seu navegador.
A ideia: mais alto que todos, mais alto que algum
Pense na fila da escola. O Pedro é mais alto que todos da turma B? Para isso ser verdade, basta ele ser mais alto que o mais alto da turma B. E ele é mais alto que algum aluno da turma B? Basta ser mais alto que o mais baixo de lá.
| Pergunta | No SQL padrão | Basta comparar com… |
|---|---|---|
| Mais alto que todos | altura > ALL (alturas da turma B) | o maior: MAX |
| Mais alto que algum | altura > ANY (alturas da turma B) | o menor: MIN |
| Mais baixo que todos | altura < ALL (…) | o menor: MIN |
| Mais baixo que algum | altura < ANY (…) | o maior: MAX |
Essa tabela é o segredo da aula: quase todo ANY/ALL com > ou < vira uma comparação com MAX ou MIN, que o SQLite tem.
1. Como se escreve nos outros bancos
A Ana quer os produtos mais caros que todos os produtos da Papelaria (categoria 1). No MySQL, no PostgreSQL ou no SQL Server, ela escreveria assim:
SELECT nome, preco FROM produtos WHERE preco > ALL (SELECT preco FROM produtos WHERE categoria_id = 1);
- preco > ALL ( … )
- "O preço é maior que cada um dos valores da subconsulta." O
ALLvem sempre logo depois de um operador de comparação (>,<,=,<>,>=,<=). - (SELECT preco FROM produtos WHERE categoria_id = 1)
- A subconsulta: uma lista de uma coluna, os 6 preços da Papelaria.
E para "mais caro que algum", troca-se ALL por ANY (ou pelo sinônimo SOME):
SELECT nome, preco FROM produtos WHERE preco > ANY (SELECT preco FROM produtos WHERE categoria_id = 1);
Segundo os manuais desses bancos: ALL é verdadeiro quando a comparação é verdadeira para todos os valores da subconsulta; ANY é verdadeiro quando ela é verdadeira para pelo menos um. Os manuais do MySQL e do PostgreSQL também dizem que IN é o mesmo que = ANY, e que NOT IN é o mesmo que <> ALL.
2. O que o SQLite faz com ANY e ALL
Agora a mesma consulta no editor do guia, que usa o SQLite de verdade:
SELECT nome, preco FROM produtos WHERE preco > ALL (SELECT preco FROM produtos WHERE categoria_id = 1);
A mensagem: near "ALL": syntax error, "erro de sintaxe perto de ALL". O SQLite conhece a palavra ALL (de UNION ALL e de SELECT ALL), mas não depois de um >. E com ANY:
SELECT nome, preco FROM produtos WHERE preco > ANY (SELECT preco FROM produtos WHERE categoria_id = 1);
A mensagem: near "SELECT": syntax error. Repare que o erro agora é "perto de SELECT", e não de ANY. Para o SQLite, ANY não é palavra especial nenhuma: ele leu ANY ( como a chamada de uma função chamada ANY, e uma função não pode ter um SELECT solto como argumento. Com SOME acontece o mesmo. Se você puser uma lista de valores no lugar da subconsulta, o SQLite confirma a suspeita:
SELECT nome FROM produtos WHERE preco = ANY (12.35, 2.79);
no such function: ANY, "não existe a função ANY". No terminal do sqlite3, as mensagens vêm com o prefixo Parse error e uma seta mostrando onde o SQLite parou de entender:
$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> SELECT nome FROM produtos WHERE preco > ALL (SELECT preco FROM produtos WHERE categoria_id = 1);
Parse error: near "ALL": syntax error
SELECT nome FROM produtos WHERE preco > ALL (SELECT preco FROM produtos WHERE
error here ---^
sqlite> SELECT nome FROM produtos WHERE preco > ANY (SELECT preco FROM produtos WHERE categoria_id = 1);
Parse error: near "SELECT": syntax error
SELECT nome FROM produtos WHERE preco > ANY (SELECT preco FROM produtos WHERE
error here ---^
A seta (error here ---^, "o erro está aqui") aponta para a palavra onde o SQLite desistiu: o ALL na primeira, o SELECT na segunda.
3. > ALL vira > MAX
Volte à fila da escola: ser mais caro que todos os produtos da Papelaria é o mesmo que ser mais caro que o mais caro deles. O mais caro da Papelaria:
SELECT MAX(preco) FROM produtos WHERE categoria_id = 1;
A mochila, a 89.99. Agora a pergunta da Ana, que roda no SQLite (e em qualquer outro banco):
SELECT nome, preco FROM produtos WHERE preco > (SELECT MAX(preco) FROM produtos WHERE categoria_id = 1) ORDER BY preco;
Cinco produtos, todos acima de 89.99: é exatamente o que > ALL devolveria. A subconsulta virou escalar (um valor só), do tipo que você viu em Subconsultas.
Missão: a Ana copiou de um tutorial de MySQL uma consulta que acha quem ganha mais que todos os vendedores e vendedoras. No SQLite, ela dá erro. Rode para ver, e depois reescreva sem ALL, comparando com o maior salário deles.
SELECT nome, salario FROM funcionarios WHERE salario > ALL (SELECT salario FROM funcionarios WHERE cargo LIKE 'Vendedor%');
SELECT nome, salario FROM funcionarios WHERE salario > (SELECT MAX(salario) FROM funcionarios WHERE cargo LIKE 'Vendedor%');
4. < ANY vira < MAX
Outra pergunta: quais brinquedos (categoria 5) são mais baratos que algum livro (categoria 4)? Na forma padrão, ilustrativa:
SELECT nome, preco FROM produtos WHERE categoria_id = 5 AND preco < ANY (SELECT preco FROM produtos WHERE categoria_id = 4);
Ser mais barato que algum livro é o mesmo que ser mais barato que o livro mais caro. Se você é mais barato que o mais caro, pelo menos esse você venceu:
SELECT nome, preco FROM produtos WHERE categoria_id = 5 AND preco < (SELECT MAX(preco) FROM produtos WHERE categoria_id = 4);
Quatro brinquedos. Só o Jogo de Tabuleiro (79.99) ficou de fora, porque o livro mais caro, o Atlas, custa 58.0. E se a pergunta fosse "mais barato que todos os livros" (< ALL)? Aí a comparação seria com o MIN, o livro mais barato (25.45).
5. = ANY é IN, <> ALL é NOT IN
Duas combinações têm tradução direta, e você já as conhece:
| SQL padrão (ilustrativo) | No SQLite | Lê-se |
|---|---|---|
id = ANY (SELECT produto_id FROM itens_pedido) | id IN (SELECT produto_id FROM itens_pedido) | "igual a algum da lista" |
id <> ALL (SELECT produto_id FROM itens_pedido) | id NOT IN (SELECT produto_id FROM itens_pedido) | "diferente de todos da lista" |
Os produtos que nunca foram vendidos, do jeito que roda aqui:
SELECT nome FROM produtos WHERE id NOT IN (SELECT produto_id FROM itens_pedido);
Lembre a armadilha da aula Subconsultas: se a lista tiver um NULL, o NOT IN (e o <> ALL, que é a mesma coisa) não devolve nada.
6. A tradução que nunca falha: EXISTS e NOT EXISTS
O MAX/MIN resolve quase sempre, mas tem um caso em que ele responde diferente do ALL: quando a subconsulta não devolve nenhuma linha. Os manuais do MySQL e do PostgreSQL dizem que, com a lista vazia, ALL é verdadeiro (não existe nenhum valor que desminta a comparação) e ANY é falso (não existe nenhum valor que a confirme).
Veja o MAX com uma categoria que não existe (a 99). A pergunta seria "brinquedos mais caros que todos os produtos da categoria 99":
SELECT nome, preco FROM produtos WHERE categoria_id = 5 AND preco > (SELECT MAX(preco) FROM produtos WHERE categoria_id = 99);
Nenhuma linha. Sem produtos, o MAX vale NULL, e nenhuma comparação com NULL é verdadeira. Já o > ALL devolveria os 5 brinquedos. Para ter exatamente o comportamento do ALL, escreva a pergunta ao contrário com NOT EXISTS: "não existe nenhum produto da categoria 99 com preço maior ou igual ao meu":
SELECT b.nome, b.preco
FROM produtos AS b
WHERE b.categoria_id = 5
AND NOT EXISTS (SELECT 1
FROM produtos AS x
WHERE x.categoria_id = 99
AND x.preco >= b.preco);
Os 5 brinquedos, como o ALL faria. Com uma categoria que existe, a forma NOT EXISTS dá o mesmo que o MAX. Os produtos mais caros que todos da Papelaria, da seção 3:
SELECT p.nome, p.preco
FROM produtos AS p
WHERE NOT EXISTS (SELECT 1
FROM produtos AS pap
WHERE pap.categoria_id = 1
AND pap.preco >= p.preco)
ORDER BY p.preco;
Os mesmos 5 produtos. E o ANY vira EXISTS: "existe algum livro mais caro que este brinquedo":
SELECT b.nome, b.preco
FROM produtos AS b
WHERE b.categoria_id = 5
AND EXISTS (SELECT 1
FROM produtos AS l
WHERE l.categoria_id = 4
AND l.preco > b.preco);
Os mesmos 4 brinquedos da seção 4.
x > ALL (lista) quer dizer "não existe na lista um valor que não seja menor que x", ou seja, nenhum valor >= x. Por isso o > virou >= dentro do NOT EXISTS: é a comparação oposta. Do mesmo jeito, x < ALL vira NOT EXISTS (… valor <= x).
7. A tabela de tradução
Encontrou um ANY/ALL num código ou tutorial? Troque assim. Na coluna do meio, a forma curta, que serve quando a lista nunca é vazia; na da direita, a que se comporta igual ao padrão até com a lista vazia.
| SQL padrão (não roda no SQLite) | Com MAX/MIN, IN | Com EXISTS |
|---|---|---|
x > ALL (SELECT v …) | x > (SELECT MAX(v) …) | NOT EXISTS (SELECT 1 … WHERE v >= x) |
x < ALL (SELECT v …) | x < (SELECT MIN(v) …) | NOT EXISTS (SELECT 1 … WHERE v <= x) |
x > ANY (SELECT v …) | x > (SELECT MIN(v) …) | EXISTS (SELECT 1 … WHERE v < x) |
x < ANY (SELECT v …) | x < (SELECT MAX(v) …) | EXISTS (SELECT 1 … WHERE v > x) |
x = ANY (SELECT v …) | x IN (SELECT v …) | EXISTS (SELECT 1 … WHERE v = x) |
x <> ALL (SELECT v …) | x NOT IN (SELECT v …) | NOT EXISTS (SELECT 1 … WHERE v = x) |
Com >= e <=, a ideia é a mesma: x >= ALL vira x >= (SELECT MAX…), e assim por diante.
MAX e MIN ignoram os NULL da lista. Já no padrão, segundo os mesmos manuais, um NULL na lista pode deixar o ALL e o ANY "desconhecidos" em vez de verdadeiros, e aí a linha não passa no WHERE. Nos dados da Loja Aurora, as colunas usadas nesta aula (preco, salario) não têm NULL. Na sua tabela, se a coluna puder ter NULL, filtre com WHERE v IS NOT NULL dentro da subconsulta e você não precisa se preocupar.
Quando dá errado
ALL depois de uma comparação
SELECT nome, salario FROM funcionarios WHERE salario > ALL (SELECT salario FROM funcionarios WHERE cargo = 'Estoquista');
A mensagem: near "ALL": syntax error. O SQLite não tem ALL em comparações.
Como consertar: salario > (SELECT MAX(salario) …), ou NOT EXISTS com a comparação invertida.
ANY ou SOME antes de uma subconsulta
SELECT nome FROM produtos WHERE id = SOME (SELECT produto_id FROM itens_pedido);
A mensagem: near "SELECT": syntax error. O SQLite tratou SOME ( como uma função e não esperava um SELECT ali dentro.
Como consertar: = ANY e = SOME são o IN: WHERE id IN (SELECT produto_id FROM itens_pedido).
A Ana queria os produtos mais caros que todos os da Papelaria e usou o MIN:
SELECT COUNT(*) AS produtos FROM produtos WHERE preco > (SELECT MIN(preco) FROM produtos WHERE categoria_id = 1);
O que acontece: 44 produtos, quase a loja inteira, sem erro. Ela perguntou "mais caro que algum" (o lápis, de 1.15), e não "mais caro que todos".
Como consertar: lembre a fila da escola. Mais que todos → compare com o extremo do outro lado (> com MAX, < com MIN). Mais que algum → com o extremo do mesmo lado (> com MIN, < com MAX).
O MySQL, o PostgreSQL e o SQL Server têm ANY, SOME e ALL depois de um operador de comparação, sempre com uma subconsulta de uma coluna. O manual do MySQL avisa que = ANY só funciona com subconsulta, não com uma lista de valores escrita à mão (para isso, use IN (1, 2, 3)). As traduções desta aula, com MAX/MIN, IN e EXISTS, rodam em todos esses bancos também, então são a escolha mais segura para quem escreve SQL que precisa funcionar em qualquer lugar.
Referência rápida
| Escrita | O que faz | No SQLite |
|---|---|---|
x > ALL (subconsulta) | Maior que todos os valores | Não existe: x > (SELECT MAX …) |
x > ANY (subconsulta) | Maior que algum valor | Não existe: x > (SELECT MIN …) |
SOME | Sinônimo de ANY | Não existe |
x = ANY (…) | Igual a algum | x IN (…) |
x <> ALL (…) | Diferente de todos | x NOT IN (…) |
| Lista vazia | ALL é verdadeiro, ANY é falso | Use NOT EXISTS / EXISTS |
| Mensagem do SQLite | Quer dizer |
|---|---|
near "ALL": syntax error | ALL depois de comparação: não existe no SQLite |
near "SELECT": syntax error | ANY (SELECT …) / SOME (SELECT …): o SQLite leu como função |
no such function: ANY | ANY (valor, valor): não existe essa função |
Exercícios
1. Mais caro que todos
Complete a tradução de preco > ALL (SELECT preco FROM produtos WHERE categoria_id = 2):
2. Igual a algum
Qual operador do SQLite faz o papel de = ANY?
3. O que o SQLite responde a WHERE preco > ALL (SELECT preco FROM produtos)?
4. "Mais barato que algum livro" (< ANY) é o mesmo que:
5. Se a subconsulta não devolver nenhuma linha, qual tradução de x > ALL (…) continua dando o mesmo resultado do padrão?
6. NOT IN é o mesmo que:
Missão final: traduza o ANY
Missão: este código veio de um banco que tem ANY e procura os brinquedos (categoria 5) mais baratos que algum livro (categoria 4). No SQLite, ele dá erro. Reescreva-o de um jeito que funcione: com MAX ou com EXISTS, você escolhe.
SELECT nome, preco FROM produtos WHERE categoria_id = 5 AND preco < ANY (SELECT preco FROM produtos WHERE categoria_id = 4);
SELECT nome, preco FROM produtos WHERE categoria_id = 5 AND preco < (SELECT MAX(preco) FROM produtos WHERE categoria_id = 4);
Resumo
x > ALL (subconsulta): maior que todos;x > ANY (subconsulta)(ouSOME): maior que algum. Existem no MySQL, no PostgreSQL e no SQL Server.- O SQLite não tem
ANY,SOMEnemALLem comparações. Os erros:near "ALL": syntax errorenear "SELECT": syntax error. - Traduza com
MAX/MIN: mais que todos → o extremo do outro lado; mais que algum → o extremo do mesmo lado. = ANYéIN;<> ALLéNOT IN.- Com a lista vazia,
ALLé verdadeiro eMAXviraNULL: para o comportamento exato do padrão, useNOT EXISTS(paraALL) eEXISTS(paraANY). Essas traduções rodam em todos os bancos.