SQL para análise de dados · Guias · 30 de outubro de 2026 · 11 min de leitura
LIKE no SQL: curingas % e _, ILIKE, NOT LIKE, acentos e escape

O LIKE filtra texto por um padrão, e não por um valor exato. O padrão tem dois curingas: % corresponde a qualquer sequência de caracteres, inclusive nenhuma, e _ corresponde a exatamente um caractere. Assim, city LIKE 'Mos%' encontra todas as cidades que começam com “Mos”, model LIKE '%300' encontra os modelos que terminam em “300” e airport_name LIKE '%ovo%' encontra os nomes que contêm “ovo” em qualquer posição. No PostgreSQL e no DuckDB, o LIKE diferencia maiúsculas de minúsculas; o ILIKE é a versão que não diferencia. O NOT LIKE inverte a correspondência, mas nenhum dos dois devolve linhas em que a coluna é NULL.
Os exemplos rodam no banco de dados de uma companhia aérea usado no curso de SQL da Nomto, com sintaxe do PostgreSQL executada no DuckDB (o motor da sala de SQL da Nomto). Os textos dos dados estão em inglês, e cada tabela de resultado saiu da execução real da consulta.
Sintaxe do LIKE
SELECT colunas
FROM tabela
WHERE coluna_de_texto LIKE 'padrão';
O padrão é uma string comum entre aspas simples. Sem curingas, o LIKE se comporta como =; são o % e o _ que o tornam útil. O padrão precisa corresponder ao valor inteiro, e é por isso que a posição do % importa tanto:
| padrão | significa | encontra |
|---|---|---|
'Mos%' |
começa com “Mos” | Moscow |
'%sk' |
termina com “sk” | Omsk, Tomsk, Irkutsk |
'%ovo%' |
contém “ovo” | Domodedovo, Pulkovo |
'_____' |
exatamente cinco caracteres | Kazan, Sochi |
'S_r%' |
S, um caractere qualquer, r, depois qualquer coisa | Saratov, Surgut |
O curinga %: começa com, termina com, contém
Começa com
SELECT airport_code, airport_name, city
FROM airports
WHERE city LIKE 'Mos%'
ORDER BY airport_code;
| airport_code | airport_name | city |
|---|---|---|
| DME | Domodedovo | Moscow |
| SVO | Sheremetyevo | Moscow |
| VKO | Vnukovo | Moscow |
Termina com
SELECT model
FROM aircrafts
WHERE model LIKE '%300'
ORDER BY model;
| model |
|---|
| Boeing 737-300 |
| Boeing 767-300 |
| Boeing 777-300 |
Contém
% dos dois lados significa “em qualquer lugar da string”:
SELECT airport_name, city
FROM airports
WHERE airport_name LIKE '%ovo%'
ORDER BY airport_name
LIMIT 6;
| airport_name | city |
|---|---|
| Domodedovo | Moscow |
| Ivanovo South | Ivanovo |
| Kemerovo | Kemerovo |
| Khomutovo | Yuzhno-Sakhalinsk |
| Khrabrovo | Kaliningrad |
| Koltsovo | Yekaterinburg |
O resultado completo tem 12 aeroportos; aqui a consulta foi cortada em seis linhas.
O “contém” pega mais do que você talvez queira. Os nomes dos passageiros estão gravados como “NOME SOBRENOME” em maiúsculas. Buscar o sobrenome Ivanov com '%IVANOV%' devolve 14.040 bilhetes, mas '% IVANOV' (um espaço e o sobrenome bem no final) devolve só 7.539:
SELECT CASE WHEN passenger_name LIKE '% IVANOV' THEN 'IVANOV'
WHEN passenger_name LIKE '% IVANOVA' THEN 'IVANOVA'
ELSE 'other' END AS surname,
COUNT(*) AS tickets
FROM tickets
WHERE passenger_name LIKE '%IVANOV%'
GROUP BY surname
ORDER BY tickets DESC;
| surname | tickets |
|---|---|
| IVANOV | 7539 |
| IVANOVA | 6501 |
O padrão frouxo pegou, sem avisar, também a forma feminina Ivanova. É o mesmo problema de buscar '%SILVA%' numa base brasileira e trazer junto “SILVANA” e “SILVEIRA”. Ancore o padrão o máximo que os dados permitirem.
O curinga _: exatamente um caractere
O _ vale por um caractere, nem mais nem menos. Cinco sublinhados encontram cidades com cinco letras:
SELECT city
FROM airports
WHERE city LIKE '_____'
ORDER BY city;
| city |
|---|
| Anapa |
| Chita |
| Kazan |
| Kirov |
| Kursk |
| Kyzyl |
| Mirny |
| Nadym |
| Penza |
| Pskov |
| Sochi |
| Tomsk |
| Ukhta |
Misturando os dois curingas: 'S_r%' significa S, depois um caractere qualquer, depois r, depois qualquer coisa.
SELECT city FROM airports WHERE city LIKE 'S_r%' ORDER BY city;
| city |
|---|
| Saransk |
| Saratov |
| Strezhevoy |
| Surgut |
Strezhevoy não é erro: S, depois “t” no lugar do sublinhado, depois “r”. O _ aceita qualquer caractere, consoantes inclusive.
Busca sem diferenciar maiúsculas: ILIKE e LOWER
No PostgreSQL e no DuckDB, o LIKE compara os caracteres exatamente, então minúscula não corresponde a maiúscula:
SELECT 'ABC' LIKE 'abc' AS like_result, 'ABC' ILIKE 'abc' AS ilike_result;
| like_result | ilike_result |
|---|---|
| false | true |
WHERE city LIKE 'mos%' não devolve nenhuma linha; WHERE city ILIKE 'mos%' devolve os três aeroportos de Moscou. O ILIKE não é SQL padrão: existe no PostgreSQL, no DuckDB e no Snowflake, mas não no MySQL nem no SQL Server. A forma portável é passar os dois lados para minúsculas:
SELECT city FROM airports WHERE lower(city) LIKE 'mos%';
No MySQL e no SQL Server, a diferenciação de maiúsculas depende da collation da coluna, e as collations padrão não diferenciam, então lá um LIKE 'mos%' simples já encontra Moscow. Essa diferença costuma surpreender quando uma consulta muda de banco.
LIKE e acentos
Em português, o problema seguinte aos maiúsculas são os acentos: quem digita “sao paulo” na busca espera encontrar “São Paulo”. Para o LIKE, “a” e “ã” são caracteres diferentes:
SELECT 'São Paulo' LIKE 'Sao%' AS like_result,
strip_accents('São Paulo') LIKE 'Sao%' AS sem_acento,
'SÃO PAULO' ILIKE 'são%' AS ilike_result;
| like_result | sem_acento | ilike_result |
|---|---|---|
| false | true | true |
O ILIKE resolve maiúsculas e minúsculas, inclusive de letras acentuadas, mas não ignora o acento. Para isso cada banco tem o seu caminho:
- DuckDB:
strip_accents(col), como acima. - PostgreSQL: a extensão
unaccent(CREATE EXTENSION unaccent;), e entãounaccent(col) ILIKE unaccent('sao%'). - MySQL: a collation padrão do MySQL 8 (
utf8mb4_0900_ai_ci) já ignora acentos e maiúsculas (o “ai” é de accent-insensitive), entãoLIKE 'sao%'encontra São Paulo. - SQL Server: depende da collation; com uma collation
_CI_AI, comoLatin1_General_CI_AI, a busca ignora maiúsculas e acentos. Dá para forçar na consulta:col COLLATE Latin1_General_CI_AI LIKE 'sao%'.
NOT LIKE, e por que as linhas NULL somem
O NOT LIKE mantém as linhas que não correspondem. A armadilha: se a coluna é NULL, tanto LIKE quanto NOT LIKE devolvem NULL, e o WHERE descarta a linha nos dois casos. Cerca de metade dos bilhetes tem um e-mail em contact_data; vamos separá-los pela presença de um sublinhado no endereço (como o \_ funciona é explicado na próxima seção):
SELECT COUNT(*) FILTER (WHERE contact_data->>'email' LIKE '%\_%' ESCAPE '\') AS with_underscore,
COUNT(*) FILTER (WHERE contact_data->>'email' NOT LIKE '%\_%' ESCAPE '\') AS without_underscore,
COUNT(*) FILTER (WHERE contact_data->>'email' IS NULL) AS no_email,
COUNT(*) AS total
FROM tickets;
| with_underscore | without_underscore | no_email | total |
|---|---|---|---|
| 87828 | 111255 | 167650 | 366733 |
LIKE mais NOT LIKE dá 199.083, e não 366.733: os 167.650 bilhetes sem e-mail não estão em nenhum dos dois grupos. Se “não corresponde” deve incluir “não tem valor”, diga isso explicitamente: WHERE email NOT LIKE '%\_%' ESCAPE '\' OR email IS NULL, ou WHERE COALESCE(email, '') NOT LIKE .... O guia de NULL no SQL explica a lógica de três valores por trás disso.
Escape: como buscar um % ou _ literal
Como % e _ são curingas, você precisa de um caractere de escape para buscar os próprios caracteres. Sem ele, “e-mails que contêm um sublinhado” corresponde a todos os e-mails:
SELECT COUNT(*) AS emails,
COUNT(*) FILTER (WHERE email LIKE '%_%') AS unescaped,
COUNT(*) FILTER (WHERE email LIKE '%\_%' ESCAPE '\') AS escaped
FROM (SELECT contact_data->>'email' AS email FROM tickets) t
WHERE email IS NOT NULL;
| emails | unescaped | escaped |
|---|---|---|
| 199083 | 199083 | 87828 |
'%_%' significa “pelo menos um caractere de qualquer tipo”, o que toda string não vazia satisfaz. Com ESCAPE '\', a sequência \_ passa a significar um sublinhado de verdade. O mesmo vale para o %: para achar descontos como “15%” num texto, use LIKE '%15\%%' ESCAPE '\'.
O caractere de escape padrão muda de banco para banco, e é aqui que as consultas quebram quando são copiadas:
- PostgreSQL usa a barra invertida como escape por padrão, então
LIKE '%\_%'funciona sem a cláusulaESCAPE. - DuckDB não tem escape padrão. O mesmo
LIKE '%\_%'semESCAPEdevolve 0 linhas nestes dados, porque procura uma barra invertida de verdade. Escreva sempreESCAPE '\'. - MySQL usa a barra invertida por padrão, como o PostgreSQL.
- SQL Server também não tem escape padrão, mas permite colocar o curinga entre colchetes:
LIKE '%[_]%'. Nos outros bancos, colchetes são caracteres comuns (o DuckDB devolve 0 linhas para esse padrão).
Uma cláusula ESCAPE explícita funciona em todos eles, e você pode escolher qualquer caractere, por exemplo LIKE '%!_%' ESCAPE '!'.
Vários padrões ao mesmo tempo
O LIKE aceita um padrão só. Para vários, combine condições com OR e coloque-as entre parênteses se houver outras condições no WHERE:
SELECT city
FROM airports
WHERE (city LIKE 'Nov%' OR city LIKE 'Nor%')
ORDER BY city;
| city |
|---|
| Norilsk |
| Novokuznetsk |
| Novosibirsk |
| Novy Urengoy |
Sem os parênteses, WHERE a AND b OR c é lido como (a AND b) OR c, uma fonte clássica de linhas a mais.
O PostgreSQL também aceita city LIKE ANY (ARRAY['Nov%', 'Nor%']). O DuckDB não: ele falha com Unsupported comparison "~~" for ANY/ALL subquery, então na sala de SQL da Nomto use OR.
Quando os padrões ficam complicados, passe para expressões regulares. No DuckDB, regexp_matches(city, '^(Nov|Nor|Noy)') devolve Norilsk, Novokuznetsk, Novosibirsk, Novy Urengoy e Noyabrsk. O PostgreSQL usa o operador city ~ '^(Nov|Nor|Noy)'. Cuidado com o ~ no DuckDB: lá ele exige que a regex corresponda à string inteira, então city ~ '^Nov' não devolve nada e você precisaria de city ~ 'Nov.*'.
LIKE vs =
= |
LIKE |
|
|---|---|---|
| Corresponde a | o valor exato | um padrão com % e _ |
| Curingas | nenhum (% é um caractere comum) |
%, _ |
| Velocidade | sempre pode usar índice | só usa índice com prefixo fixo |
| Uso típico | status = 'Arrived' |
city LIKE 'Nov%' |
Use = sempre que souber o valor completo. Sem curingas, o LIKE dá o mesmo resultado que o = no PostgreSQL e no DuckDB ('abc ' LIKE 'abc' e 'abc ' = 'abc' são ambos falsos). No SQL Server, o = ignora espaços no final, mas o LIKE os leva em conta, então lá 'abc ' = 'abc' é verdadeiro e 'abc' LIKE 'abc ' é falso.
O LIKE também funciona com datas convertidas em texto, CAST(scheduled_departure AS VARCHAR) LIKE '2026-08-01%', e aqui dá os mesmos 568 voos que um intervalo. Prefira o intervalo, scheduled_departure >= '2026-08-01' AND scheduled_departure < '2026-08-02': ele mantém o tipo da coluna, funciona em qualquer banco seja qual for o formato de data em texto (no SQL Server, um CAST de data para texto sem estilo dá algo como Aug 1 2026 12:00AM) e pode usar índice. Mais sobre isso no guia de funções de data no SQL.
Desempenho do LIKE
Numa tabela grande, o jeito como o padrão começa decide a velocidade:
- Um prefixo fixo (
'Mos%') pode usar um índice B-tree, porque todos os valores correspondentes ficam juntos na ordem. No PostgreSQL isso funciona de fábrica só com a collationC; com outras collations (comopt_BR.UTF-8) você precisa de um índice criado comtext_pattern_ops(ouvarchar_pattern_ops). - Um curinga no início (
'%ovo'ou'%ovo%') não usa um índice comum: o banco precisa ler todos os valores. No PostgreSQL, um índice de trigramas (a extensãopg_trgmcom um índice GIN ou GiST) deixa as buscas por “contém” rápidas. lower(col) LIKE ...eILIKEnão usam um índice simples emcol. No PostgreSQL, crie um índice emlower(col)para o primeiro; oILIKEprecisa de um índice de trigramas.
Motores analíticos colunares, como DuckDB, BigQuery ou Snowflake, varrem colunas rapidamente de qualquer forma, então num conjunto de dados do tamanho do curso você não vai notar a diferença. Numa tabela de produção com milhões de linhas no PostgreSQL ou no MySQL, vai.
Erros comuns
- Esquecer o curinga.
WHERE city LIKE 'Mos'só encontra uma cidade chamada exatamente “Mos”. - Aspas duplas em volta do padrão. No PostgreSQL e no DuckDB,
"Mos%"é um nome de coluna, não uma string. Use aspas simples. %dos dois lados quando você queria um prefixo. Mais lento e pega demais, como mostra o exemplo Ivanov/Ivanova._sem escape no padrão.LIKE 'view_%'encontra “view_offer”, mas também “viewX” ou “views”; use escape se quer um sublinhado de verdade.- Esperar que o
NOT LIKEdevolva linhas NULL. Ele nunca devolve; acrescenteOR col IS NULL. - Esquecer os acentos.
LIKE 'Sao%'não encontra “São Paulo” no PostgreSQL nem no DuckDB. - Misturar
ANDeORsem parênteses ao combinar vários padrões.
Para extrair partes das strings depois de encontrá-las (SPLIT_PART, SUBSTRING, REPLACE), veja o guia de funções de texto no SQL. Os filtros por padrão também estão na cola de SQL.
Perguntas frequentes
O que significa % no LIKE do SQL?
O % corresponde a qualquer sequência de caracteres, inclusive uma vazia. 'Mos%' encontra “Mos”, “Moscow” e qualquer outra coisa que comece com “Mos”. O _ corresponde a exatamente um caractere.
O LIKE diferencia maiúsculas de minúsculas?
No PostgreSQL, no DuckDB e no Oracle, sim. No MySQL e no SQL Server depende da collation, e as collations padrão não diferenciam. Para uma busca sem diferenciar no PostgreSQL ou no DuckDB, use ILIKE, ou lower(col) LIKE 'padrão' em qualquer banco.
Como fazer o LIKE ignorar acentos?
Remova os acentos dos dois lados antes de comparar: strip_accents no DuckDB, a extensão unaccent no PostgreSQL. No MySQL 8 a collation padrão já ignora acentos; no SQL Server, use uma collation _AI, por exemplo COLLATE Latin1_General_CI_AI.
Como escapar um sublinhado ou um sinal de porcentagem no LIKE?
Coloque um caractere de escape antes dele e declare-o com ESCAPE: col LIKE '%\_%' ESCAPE '\' encontra valores com um sublinhado de verdade. PostgreSQL e MySQL usam a barra invertida por padrão; DuckDB e SQL Server não, então a cláusula ESCAPE explícita é a forma portável. O SQL Server também aceita '%[_]%'.
Posso usar LIKE com vários valores?
Não diretamente. Combine condições com OR (city LIKE 'Nov%' OR city LIKE 'Nor%'), use LIKE ANY (ARRAY[...]) no PostgreSQL ou passe para uma expressão regular.
O LIKE é mais lento que o =?
Um LIKE com prefixo fixo pode usar índice e é quase tão rápido quanto o =. Um padrão que começa com % precisa verificar todas as linhas, o que é bem mais lento em tabelas grandes, a menos que você crie um índice de trigramas (PostgreSQL) ou um índice de texto completo.
Outros idiomas: English, Español, Tiếng Việt, 简体中文