SQL NOT

Às vezes é mais fácil dizer o que você não quer. A Ana vai mandar um cartão para todos os clientes da Loja Aurora que moram fora do Piauí. Em vez de listar os outros estados um por um, ela pode pedir "todos, menos os do Piauí". É para isso que serve o NOT ("não", em inglês): ele inverte uma condição do WHERE. O que era verdadeiro vira falso, e o que era falso vira verdadeiro.

Você vai aprender
  • Como o NOT inverte uma condição do WHERE.
  • O NOT em colunas de "sim ou não" (0 e 1), como vip e descontinuado.
  • A ordem em que o SQL lê NOT, AND e OR, e por que os parênteses mudam tudo.
  • A troca de NOT (A OR B) por NOT A AND NOT B.
  • A armadilha do NULL: por que "não é do Piauí" deixa de fora quem não tem estado nenhum.
  • Os parentes do NOT: NOT LIKE, NOT IN, NOT BETWEEN, IS NOT NULL.

Os exemplos usam o banco da Loja Aurora. Cada quadro "Resultado" é desenhado pelo SQLite de verdade, rodando no seu navegador. Se ainda não viu o WHERE, comece por WHERE; o NOT conversa muito com AND e OR, das aulas anteriores.


A ideia: tirar da pilha

Imagine as fichas dos 30 clientes da loja numa pilha em cima da mesa. A Ana pode fazer dois pedidos diferentes ao ajudante:

PedidoEm SQLO que sobra na mão
"Separe as fichas do Piauí."WHERE estado = 'PI'Só as fichas do Piauí
"Separe as fichas que não são do Piauí."WHERE NOT estado = 'PI'Todas as outras

O ajudante faz a mesma pergunta para cada ficha ("é do Piauí?"), mas, com o NOT, fica com as fichas em que a resposta foi não. O NOT não muda a pergunta; ele troca a resposta.


1. O primeiro NOT

Os clientes que não moram no Piauí:

SELECT nome, cidade, estado
FROM clientes
WHERE NOT estado = 'PI';
WHERE
"Onde": o filtro. Só passam as linhas em que a condição dá verdadeiro.
NOT
"Não": inverte a condição que vem logo depois dele.
estado = 'PI'
A condição original: "o estado é PI?". Para José Ribamar (PI) a resposta é sim; para Ana Beatriz (SP), não.
NOT estado = 'PI'
A condição invertida: para José Ribamar, o "sim" virou "não", e ele fica de fora; para Ana Beatriz, o "não" virou "sim", e ela entra.

Resultado: 16 clientes, de São Paulo, Fortaleza e Recife. Os outros 14 moram no Piauí (Teresina, Parnaíba, Picos, Oeiras, Floriano). 16 + 14 = 30, a tabela inteira: o NOT pegou exatamente o "resto".

O NOT vai antes da condição inteira

Repare na posição: NOT estado = 'PI', com o NOT na frente. O SQL lê isso como NOT (estado = 'PI'): primeiro compara, depois inverte. Escrever o NOT no meio, como em português ("estado não igual a PI"), dá erro; você vai ver em Quando dá errado.


2. Verdadeiro e falso no SQLite: 1 e 0

Para entender o NOT de verdade, vale ver o que ele faz com um valor solto. No SQLite, "verdadeiro" é 1 e "falso" é 0. Você pode perguntar direto, sem tabela nenhuma:

SELECT NOT 1, NOT 0, NOT 5, NOT NULL;
ExpressãoResultadoPor quê
NOT 101 é verdadeiro; o contrário é falso (0).
NOT 010 é falso; o contrário é verdadeiro (1).
NOT 50Qualquer número diferente de 0 conta como verdadeiro.
NOT NULLNULLNULL é "não sei". O contrário de "não sei" continua "não sei". Guarde isso: é a armadilha da seção 6.

Colunas de sim ou não

A Loja Aurora guarda "sim ou não" como 1 ou 0. A coluna vip dos clientes é 1 para os 5 clientes VIP e 0 para os outros. A coluna descontinuado dos produtos é 1 para os produtos que a loja parou de vender. Para ver os produtos que não são "não descontinuados" (ou seja, os descontinuados):

SELECT nome, preco, estoque
FROM produtos
WHERE NOT descontinuado = 0;

Dois produtos, os dois com estoque 0. Esse exemplo é de propósito "torto", para você treinar a leitura: "não é igual a zero" é o mesmo que "é igual a 1". Na vida real, a Ana escreveria WHERE descontinuado = 1, que é mais fácil de ler.

Como 0 já é falso e 1 já é verdadeiro, no SQLite dá até para usar a coluna sozinha. Os clientes que não são VIP:

SELECT nome, vip
FROM clientes
WHERE NOT vip;

25 clientes, todos com vip 0. Para o cliente 2 (Maria Clara), vip é 0, NOT 0 é 1 (verdadeiro), e ela entra. Para o cliente 1 (José Ribamar), vip é 1, NOT 1 é 0, e ele fica de fora. É o mesmo que WHERE NOT vip = 1 ou WHERE vip = 0.

Atalho que não funciona em todo banco

WHERE NOT vip funciona no SQLite e no MySQL, mas não em todos os bancos (veja Nos outros bancos). Se você quer um SQL que roda em qualquer lugar, escreva a comparação inteira: WHERE vip = 0.

Experimente: a categoria 1 da loja é a Papelaria. Mostre os produtos que não são da Papelaria, colocando um NOT no lugar certo. Devem aparecer 39 produtos.

SELECT nome, categoria_id
FROM produtos
WHERE categoria_id = 1;
SELECT nome, categoria_id
FROM produtos
WHERE NOT categoria_id = 1;

3. NOT junto com AND: a ordem importa

A Ana quer os clientes VIP que não são do Piauí. Ela escreve:

SELECT nome, cidade, estado, vip
FROM clientes
WHERE NOT estado = 'PI' AND vip = 1;

Três clientes: Ana Beatriz (SP), Fernanda e Mirela (CE). Deu certo porque o SQL lê as partes nesta ordem:

  1. Primeiro as comparações: estado = 'PI' e vip = 1.
  2. Depois o NOT, que inverte só a comparação que está colada nele: estado = 'PI'.
  3. Depois o AND, que junta as duas partes.
  4. Por último, o OR (se houver).

Ou seja, o SQL entendeu (NOT estado = 'PI') AND (vip = 1). Agora veja o que acontece com parênteses em volta das duas condições:

SELECT nome, cidade, estado, vip
FROM clientes
WHERE NOT (estado = 'PI' AND vip = 1);

28 clientes! Agora o NOT inverte a pergunta inteira que está dentro dos parênteses: "é do Piauí e é VIP?". Só dois clientes respondem "sim" a ela (José Ribamar e Larissa, os VIPs do Piauí); com o NOT, saem esses dois e ficam os outros 28. Parece uma diferença pequena na escrita, mas a pergunta mudou completamente.

EscritaPergunta em portuguêsLinhas
NOT estado = 'PI' AND vip = 1Não é do Piauí, e é VIP3
NOT (estado = 'PI' AND vip = 1)Não é verdade que é do Piauí e VIP ao mesmo tempo28
Na dúvida, parênteses

Parênteses nunca atrapalham. (NOT estado = 'PI') AND vip = 1 dá o mesmo resultado da primeira consulta, e quem lê não precisa lembrar da ordem. Quando juntar NOT, AND e OR, use parênteses para deixar a sua intenção clara.


4. NOT de um OR: a troca de De Morgan

A Ana quer os clientes que nem são do Piauí nem são VIP: os que vão receber um cupom de boas-vindas para conhecer a loja. Dá para escrever de dois jeitos:

SELECT nome, cidade, estado, vip
FROM clientes
WHERE NOT (estado = 'PI' OR vip = 1);
SELECT nome, cidade, estado, vip
FROM clientes
WHERE NOT estado = 'PI' AND NOT vip = 1;

Os dois devolvem os mesmos 13 clientes. Essa troca tem nome: é a lei de De Morgan, de um matemático inglês do século XIX. Ela diz:

Isto……é o mesmo que istoEm português
NOT (A OR B)NOT A AND NOT B"Nem A nem B"
NOT (A AND B)NOT A OR NOT B"Não as duas coisas ao mesmo tempo"

Quando o NOT "entra" nos parênteses, ele inverte cada pedaço e troca o OR por AND (ou o AND por OR). O erro clássico é inverter os pedaços e esquecer de trocar o conector.


5. NOT com mais de uma condição negada

A Ana quer os clientes das cidades "pequenas" da lista, as que não são as três maiores (Teresina, São Paulo e Fortaleza):

SELECT nome, cidade
FROM clientes
WHERE NOT cidade = 'Teresina'
  AND NOT cidade = 'São Paulo'
  AND NOT cidade = 'Fortaleza';

Seis clientes, de Parnaíba, Recife, Picos, Oeiras e Floriano. Funciona, mas repare como ficou comprido. Para "não é nenhum destes", o SQL tem um jeito mais curto, o NOT IN, que você vai ver na aula IN:

SELECT nome, cidade
FROM clientes
WHERE cidade NOT IN ('Teresina', 'São Paulo', 'Fortaleza');

O NOT aparece "grudado" em vários outros operadores do SQL. Cada um tem a sua aula; aqui vai só o mapa:

OperadorQuer dizerExemploAula
NOT LIKENão combina com o padrão de textonome NOT LIKE 'Ana %'LIKE
NOT INNão é nenhum dos valores da listacidade NOT IN ('Teresina', 'Recife')IN
NOT BETWEENEstá fora da faixapreco NOT BETWEEN 10 AND 200BETWEEN
IS NOT NULLTem algum valor (não está vazio)email IS NOT NULLIS NULL

Nos três primeiros, o NOT pode ir antes da coluna também: NOT nome LIKE 'Ana %' e nome NOT LIKE 'Ana %' dão o mesmo resultado (28 clientes, todos menos as duas Anas). A forma com o NOT no meio é a mais comum, porque se lê como português.


6. A armadilha do NULL

A Loja Aurora tem 6 fornecedores. Dois são do Piauí (a Distribuidora Piauí Center e a Norte Suprimentos). A Ana pede os que não são do Piauí, esperando ver os outros quatro:

SELECT nome, estado
FROM fornecedores
WHERE NOT estado = 'PI';

Vieram só dois. Sumiram a Lusitana Comércio (de Portugal) e a Pampa Sur (da Argentina). Elas não são do Piauí, então por que não apareceram? Porque fornecedor estrangeiro não tem estado brasileiro: a coluna estado deles é NULL (vazia, "não sei"). Veja o que o SQLite calcula em cada linha:

SELECT nome, estado, estado = 'PI', NOT estado = 'PI'
FROM fornecedores;

Nas duas últimas linhas da conta, a comparação estado = 'PI' deu NULL: o SQLite não sabe se um valor desconhecido é igual a 'PI'. E, como você viu na seção 2, NOT NULL continua NULL. O WHERE só deixa passar o que é verdadeiro; "não sei" não é verdadeiro, e a linha fica de fora.

estadoestado = 'PI'NOT estado = 'PI'Passa no WHERE?
PI1 (verdadeiro)0 (falso)Não
CE0 (falso)1 (verdadeiro)Sim
NULLNULL (não sei)NULL (não sei)Não

O mesmo acontece com os 3 clientes sem email: WHERE NOT email LIKE '%@exemplo.com.br' devolve 0 linhas, e não os 3 clientes que não têm esse email. Linhas com NULL na coluna testada nunca passam por um NOT, nem pela condição sem NOT.

Para incluir os estrangeiros, diga com todas as letras que o NULL também serve:

SELECT nome, estado
FROM fornecedores
WHERE NOT estado = 'PI' OR estado IS NULL;

Agora são os quatro. O IS NULL ("é vazio") é a única pergunta que responde "sim" para um NULL; ele tem aula própria, IS NULL e IS NOT NULL, e o próprio NULL é explicado em O Valor NULL.

Missão: a consulta abaixo deveria listar os fornecedores de fora do Piauí, mas esquece os dois estrangeiros. Conserte para que apareçam os 4 fornecedores.

SELECT nome, cidade, estado, pais
FROM fornecedores
WHERE NOT estado = 'PI';
SELECT nome, cidade, estado, pais
FROM fornecedores
WHERE NOT estado = 'PI' OR estado IS NULL;

7. Formas diferentes de dizer "não"

Para "o estado não é PI", o SQL aceita várias escritas. Nos clientes, todas dão os mesmos 16:

EscritaObservação
WHERE NOT estado = 'PI'O NOT desta aula.
WHERE NOT (estado = 'PI')Igual, com parênteses deixando claro o que é invertido.
WHERE estado <> 'PI'"Diferente de", o operador padrão do SQL (aula Comparações).
WHERE estado != 'PI'Outra escrita de "diferente", aceita pelo SQLite e pelos bancos mais usados.

Todas as quatro têm a mesma armadilha do NULL: nenhuma delas deixa passar os fornecedores estrangeiros.

SituaçãoQual usar
Uma comparação simples ("não é igual a")<>: mais curto e todo mundo entende.
Inverter uma condição composta, com AND/ORNOT ( … ), sempre com parênteses.
"Não combina", "não está na lista", "fora da faixa", "não é vazio"NOT LIKE, NOT IN, NOT BETWEEN, IS NOT NULL.
Coluna de sim/não (0 e 1)vip = 0, que roda em qualquer banco; NOT vip só onde o banco aceita.
A coluna pode ter NULL e você quer essas linhas tambémAcrescente OR coluna IS NULL.

Quando dá errado

O NOT no meio, como em português

Em português se diz "estado não igual a PI", e a Ana escreveu assim:

SELECT nome FROM clientes WHERE estado NOT = 'PI';

A mensagem: near "=": syntax error, "perto de =: erro de sintaxe". O SQL até aceita um NOT depois da coluna, mas só quando vem um LIKE, IN, BETWEEN… em seguida. Um = logo depois do NOT não faz sentido para ele. No terminal do sqlite3, a mesma mensagem vem com o prefixo Parse error e uma seta apontando o lugar:

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> SELECT nome FROM clientes WHERE estado NOT = 'PI';
Parse error: near "=": syntax error
  SELECT nome FROM clientes WHERE estado NOT = 'PI';
                               error here ---^
sqlite> .quit

Como consertar: o NOT vai antes da condição (NOT estado = 'PI'), ou use o "diferente": estado <> 'PI'.

Usou ! no lugar de NOT

Quem vem de outras linguagens de programação (JavaScript, PHP, C) está acostumado com o ! para "não":

SELECT nome FROM clientes WHERE ! vip;

A mensagem: unrecognized token: "!", "símbolo desconhecido: !". No SQLite, o ! sozinho não existe; ele só aparece grudado no =, em !=.

Como consertar: escreva a palavra NOT: WHERE NOT vip, ou melhor ainda, WHERE vip = 0.

Esqueceu as aspas do texto
SELECT nome FROM clientes WHERE NOT estado = PI;

A mensagem: no such column: PI, "não existe a coluna PI". Sem aspas, o SQL acha que PI é o nome de uma coluna. Isso não tem nada a ver com o NOT, mas acontece muito quando se reescreve a condição às pressas.

Como consertar: texto vai entre aspas simples: 'PI'.

Sem erro nenhum, mas faltaram linhas (o NULL)

O caso mais perigoso não tem mensagem: é o da seção 6. WHERE NOT estado = 'PI' nos fornecedores roda sem reclamar e devolve 2 linhas, quando a Ana esperava 4. O SQLite fez exatamente o que foi pedido: as linhas com estado NULL deram "não sei", e "não sei" não passa no WHERE.

Como evitar: antes de usar NOT (ou <>) numa coluna, pergunte-se: "essa coluna pode estar vazia?". Se puder, acrescente OR coluna IS NULL. Uma conferência rápida: o "sim" mais o "não" tem de dar o total da tabela. Aqui, 2 do Piauí + 2 fora = 4, mas a tabela tem 6.

O NOT inverteu mais (ou menos) do que você queria

Também sem mensagem de erro: NOT estado = 'PI' AND vip = 1 (3 linhas) e NOT (estado = 'PI' AND vip = 1) (28 linhas) são perguntas diferentes, como você viu na seção 3. Se o número de linhas parecer estranho, confira onde estão os parênteses.

Nos outros bancos
  • MySQL e MariaDB aceitam o ! como sinônimo de NOT (WHERE ! vip), mas a documentação do MySQL diz que ele é uma extensão fora do padrão, obsoleta, e que pode ser removida: use NOT.
  • PostgreSQL tem um tipo boolean de verdade (true/false), e o NOT dele é feito para esse tipo. Numa coluna de números 0 e 1 como a vip, o atalho NOT vip não serve; escreva a comparação inteira: vip = 0. Ilustrativo (não roda no SQLite):
-- PostgreSQL, com uma coluna do tipo boolean
SELECT nome FROM clientes WHERE NOT vip;      -- vip é boolean: funciona
SELECT nome FROM clientes WHERE vip = false;  -- o mesmo, por extenso

Com NOT coluna = valor, NOT ( … ) e os parentes (NOT LIKE, NOT IN…), o SQL desta aula é o padrão e funciona igual nos bancos mais usados, inclusive a armadilha do NULL.


Referência rápida

EscritaO que faz
WHERE NOT condiçãoPassam as linhas em que a condição é falsa
NOT (A AND B)Inverte a condição composta inteira; o mesmo que NOT A OR NOT B
NOT (A OR B)"Nem A nem B"; o mesmo que NOT A AND NOT B
NOT A AND BO NOT pega só o A: (NOT A) AND B
NOT 1 / NOT 0 / NOT NULL0 / 1 / NULL
NOT LIKE, NOT IN, NOT BETWEEN, IS NOT NULLAs formas "não" dos outros operadores
Ordem de leituraComparações → NOT → AND → OR (parênteses primeiro)
Mensagem do SQLiteQuer dizer
near "=": syntax errorUm NOT no meio, antes do = (estado NOT = 'PI')
unrecognized token: "!"Usou ! no lugar de NOT
no such column: PITexto sem aspas simples

Exercícios

1. Os produtos que ainda estão à venda

Complete para mostrar os produtos que não estão descontinuados:

SELECT nome FROM produtos WHERE descontinuado = 1;

2. O valor do NOT

Quanto o SQLite responde para SELECT NOT 0;?

3. Qual destas escritas dá erro de sintaxe no SQLite?

4. Qual escrita é igual a NOT (estado = 'PI' OR vip = 1)?

5. A tabela fornecedores tem 6 linhas: 2 com estado PI, 2 com CE e SP, e 2 com estado NULL. Quantas linhas WHERE NOT estado = 'PI' devolve?

Missão final: o cupom de boas-vindas

Missão: a Ana vai mandar um cupom para os clientes que não moram em Teresina e que não são VIP. A consulta abaixo traz os clientes de Teresina; mude o WHERE para trazer os clientes certos (são 17).

SELECT nome, cidade, vip
FROM clientes
WHERE cidade = 'Teresina';
SELECT nome, cidade, vip
FROM clientes
WHERE NOT cidade = 'Teresina' AND NOT vip = 1;

Conseguiu? Tente também a forma com parênteses, NOT (cidade = 'Teresina' OR vip = 1), e confira que dá os mesmos 17. Nenhum cliente tem cidade vazia, então aqui a armadilha do NULL não aparece.


Resumo

  • NOT ("não") inverte uma condição: o WHERE passa a ficar com as linhas em que ela é falsa.
  • No SQLite, verdadeiro é 1 e falso é 0: NOT 1 dá 0, NOT 0 dá 1. Por isso WHERE NOT vip funciona, mas vip = 0 roda em qualquer banco.
  • O NOT vem antes da condição: NOT estado = 'PI'. Escrito no meio (estado NOT = 'PI'), dá near "=": syntax error.
  • Ordem: comparações, depois NOT, depois AND, depois OR. NOT A AND B inverte só o A; para inverter tudo, use parênteses.
  • De Morgan: NOT (A OR B) = NOT A AND NOT B; NOT (A AND B) = NOT A OR NOT B.
  • NOT NULL continua NULL: linhas com a coluna vazia ficam de fora tanto da condição quanto do NOT. Para incluí-las, acrescente OR coluna IS NULL.