Fala meu povo,
Nesse post vamos aprender vários conceitos sobre o operador LIKE e responder a seguinte pergunta:
Qual a diferença entre LIKE ‘%_TEXTO%’ e ‘%[_]TEXTO%’?
1 2 3 4 5 6 7 |
SELECT * FROM Produto WHERE Nome LIKE '%_TEXTO%' SELECT * FROM Produto WHERE Nome LIKE '%[_]TEXTO%' |
A) Nenhum. Ambos vão retornar sempre o mesmo resultado.
B) Ao utilizar ‘%[_]TEXTO%’ será gerado um erro de sintaxe na query.
C) A opção ‘%[_]TEXTO%’ irá retornar pelo menos os mesmos resultados do que a opção ‘%_TEXTO%’.
D) A opção ‘%_TEXTO%’ irá retornar pelo menos os mesmos resultados do que a opção ‘%[_]TEXTO%’.
E) A opção ‘%_TEXTO%’ irá retornar obrigatoriamente o texto “_TEXTO”.
Antes de continuar a leitura do post, escolha a sua opção e espero que ao final você entenda qual é a alternativa correta. #gogogo =)
Exemplo – LIKE ‘%_TEXTO%’:
Vou mostrar primeiro o exemplo da utilização do LIKE e depois vou explicar um pouco mais esse operador.
Imagine que você é o DBA da empresa e que lá existem 10 desenvolvedores que vivem fazendo cagada no banco de dados (cenário normal de qualquer empresa xD), brincadeira, nós adoramos os DEVs e eles são todos nossos amiguinhos. #paz
Os desenvolvedores possuem um péssimo hábito de criar algumas tabelas de backup antes de fazer algum tipo de alteração ou correção no ambiente e depois esquecem de excluí-las. Por exemplo, tabela “Clientes_BKP20200625” (vai dizer que você nunca fez isso??? ÇÇeiii!!! Eu já fui DEV e já fiz isso também hehehe).
Um determinado dia, você acabou encontrando essa tabela “Clientes_BKP20200625” e viu que ela estava ocupando 50 GB de espaço em disco. Puto da vida, você foi lá puxar a orelha dos DEVs. Mal sabia você que isso era apenas a ponta do iceberg e acabou descobrindo que tinha dezenas de tabelas dessa forma e que elas não eram mais necessárias.
Sua Missão:
Toda essa historinha foi pra mostrar a nossa tarefa para listar todas as tabelas de backup com o seguinte padrão: “NomeTabela_BKP…”. Com isso, podemos fazer um filtro em todas as tabelas da database que possuem o texto “_BKP” no nome OK.
“Ah Luiz, essa é mole! É só fazer um LIKE ‘%_BKP%’ e pronto!”
Beleza, bora testar então!
Inicialmente, vou criar quatro tabelas:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
USE Traces -- 2017 CREATE TABLE TABELA_BKP20170101 (ID INT) -- 2018 CREATE TABLE TABELA_BKP20180101 (ID INT) -- 2019 CREATE TABLE TABELABKP20190101 (ID INT) -- 2020 CREATE TABLE TABELABKP20200101 (ID INT) |
Depois vou fazer um SELECT e validar as tabelas que possuem o texto “_BKP” no nome utilizando o LIKE ‘%_TEXTO%’.
1 2 3 |
SELECT name, create_date, modify_date FROM sys.tables WHERE name LIKE '%_BKP%' |
Repare que esse SELECT retornou também algumas tabelas apenas com o texto “BKP” sem o caractere “_”.

“Eiiita, e como eu resolvo isso Luiz???”
Calma, vamos fazer o mesmo SELECT, mas dessa vez utilizando o LIKE ‘%[_]TEXTO%’.
1 2 3 |
SELECT name, create_date, modify_date FROM sys.tables WHERE name LIKE '%[_]BKP%' |
Agora sim conseguimos retornar apenas as tabelas que possuem obrigatoriamente o texto “_BKP” no nome!

Entendido esse exemplo, agora vamos explicar melhor o operador LIKE!
Operador LIKE:
Segue abaixo um link da documentação oficial da Microsoft sobre o LIKE:
https://docs.microsoft.com/pt-br/sql/t-sql/language-elements/like-transact-sql?view=sql-server-ver15
Também recomendo a leitura do post abaixo (em inglês) que tem vários exemplos bem simples de entender.
Como sempre, o mestre Dirceu Resende também tem um post sobre esse assunto com mais alguns exemplos legais. =)
O operador LIKE é utilizado para retornar um registro se uma determinada string for encontrada.
Vamos criar uma tabela chamada “Cliente” e inserir alguns registros. Depois vamos ver alguns exemplos para entender o funcionamento do LIKE.
1 2 3 4 5 6 7 8 |
USE Traces CREATE TABLE Cliente (Nome VARCHAR(100)) INSERT INTO Cliente VALUES ('Dirceu Resende'),('Fabricio Lima'), ('Luiz Lima'), ('Rodrigo Ribeiro') SELECT * FROM Cliente |

LIKE ‘%TEXTO%’ -> Busca a string “TEXTO” em qualquer lugar do registro, seja no início, no meio ou no fim.
1 2 3 |
SELECT * FROM Cliente WHERE Nome LIKE '%sen%' |

LIKE ‘TEXTO%’ -> Busca os registros que iniciam com a string “TEXTO”.
1 2 3 |
SELECT * FROM Cliente WHERE Nome LIKE 'Rod%' |

LIKE ‘%TEXTO’ -> Busca os registros que terminam com a string “TEXTO”.
1 2 3 |
SELECT * FROM Cliente WHERE Nome LIKE '%Lima' |

LIKE ‘TEXTO%TEXTO%TEXTO’ -> Também é possível fazer uma combinação dos casos anteriores. Aqui vou buscar os registros que iniciam com “L”, possuem o “Li” no meio e terminam com “a”.
1 2 3 |
SELECT * FROM Cliente WHERE Nome LIKE 'L%Li%a' |

Wildcard Character:
Voltando ao nosso exemplo das Tabelas de Backup, agora vou explicar o Wildcard Character (ou caractere curinga). Por padrão, o SQL Server representa esse caractere com o “_” (underscore).
Ao utilizar o caractere “_“, o SQL Server retorna qualquer caractere nessa posição específica, ou seja, não importa. No próximo exemplo vamos utilizar o LIKE ‘%_BKP%’ para retornar todas as tabelas que possuem a string “BKP” e qualquer outro caractere antes dela, não importa qual seja.
1 2 3 |
SELECT name, create_date, modify_date FROM sys.tables WHERE name LIKE '%_BKP%' |

“Oh Luiz, mas eu quero retornar obrigatoriamente a string ‘_BKP’ e não qualquer um caractere antes. Como eu faço isso então?”
Nesse caso, vamos precisar utilizar os colchetes da seguinte forma: LIKE ‘%[_]BKP%’. Agora sim iremos retornar apenas os registros que possuem obrigatoriamente a string “_BKP”.
1 2 3 |
SELECT name, create_date, modify_date FROM sys.tables WHERE name LIKE '%[_]BKP%' |

Com isso, podemos perceber que o LIKE ‘%_TEXTO%’ sempre vai retornar pelo menos a mesma quantidade de registros que o LIKE ‘%[_]TEXTO%’.

Diferença entre ‘_’ e ‘%’:
Também é importante explicar a diferença ao utilizar o “_” e “%”.
“_” -> Substitui apenas um caractere obrigatoriamente.
“%” -> Substitui zero ou mais caracteres.
Vou criar uma tabela e inserir alguns registros.
1 2 3 4 5 6 |
CREATE TABLE Teste_Tamanho (Nome VARCHAR(100)) INSERT INTO Teste_Tamanho VALUES ('Aqui tem uma string'),('Aqui tem uma string e mais alguma coisa'),('a') SELECT * FROM Teste_Tamanho |

Agora vou fazer dois filtros, um usando “_” e outro o “%”.
1 2 3 4 5 6 7 8 |
-- DIFERENÇA ENTRE "_" E "%" SELECT * FROM Teste_Tamanho WHERE Nome LIKE '_a' SELECT * FROM Teste_Tamanho WHERE Nome LIKE '%a' |
Repare que o primeiro SELECT não retornou nada, pois ao usar o LIKE ‘_a’ ele não encontra nenhum registro que tenha obrigatoriamente algo antes do “a”.
Já no segundo SELECT, como utilizamos o LIKE ‘%a’, ele também não encontra nenhum registro com nada antes do “a”, mas nesse caso o % vai ser substituído por uma string vazia ou por qualquer coisa que venha antes, independente do tamanho. Com isso, o SQL Server vai encontrar dois registros, um que inicia e outro que termina com o “a”.

LIKE ‘%’ – String com Tamanho Fixo x Variável:
Vamos fazer mais um teste para explicar um outro comportamento do ‘%’.
Quando usamos o LIKE ‘TEXTO’, o SQL Server vai procurar um registro que tenha exatamente esse texto e o mesmo tamanho. Esse é o caso do primeiro SELECT.
Já no segundo SELECT, utilizamos o LIKE ‘TEXTO%’ e dessa vez o SQL Server vai retornar qualquer registro que inicie com essa string, independente do tamanho que ela tenha depois.
1 2 3 4 5 6 7 8 9 |
-- TAMANHO FIXO SELECT * FROM Teste_Tamanho WHERE Nome LIKE 'Aqui tem uma string' -- TAMANHO VARIAVEL SELECT * FROM Teste_Tamanho WHERE Nome LIKE 'Aqui tem uma string%' |

LISTA E RANGE – LIKE ‘[ABCD]’ x LIKE ‘[A-Z]’ x LIKE ‘[^ABCD]’
Também podemos utilizar o LIKE para retornar alguns padrões utilizando uma LISTA ou um RANGE. Por exemplo:
LISTA – LIKE ‘[ABCD]’ -> Ao utilizar o [ABCD] vamos buscar os registros que iniciam com A, B, C ou D.
RANGE – LIKE ‘[A-F]%’ – > Ao utilizar o [A-F] vamos buscar os registros que iniciam com A até F.
DESCONSIDERAR “^” – LIKE ‘[^A-F]%’ – > Ao utilizar o [^A-F] vamos DESCONSIDERAR os registros que iniciam com A até F.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
-- 1) NOMES QUE INICIAM DE "A" ATE "F" SELECT * FROM Cliente WHERE Nome LIKE '[A-F]%' -- 2) NOMES QUE INICIAM DE "G" ATE "Z" SELECT * FROM Cliente WHERE Nome LIKE '[G-Z]%' -- 3) NOMES QUE INICIAM COM "D" OU "L" SELECT * FROM Cliente WHERE Nome LIKE '[DL]%' -- 4) NOMES QUE NÃO INICIAM DE "A" ATE "F" SELECT * FROM Cliente WHERE Nome LIKE '[^A-F]%' |

NOT LIKE:
Também podemos utilizar o NOT LIKE para desconsiderar alguns registros. No exemplo abaixo, não queremos retornar os clientes que possuem “Lima” no nome.
1 2 3 |
SELECT * FROM Cliente WHERE Nome NOT LIKE '%Lima%' |

ESCAPE:
Wildcard Characters -> ‘%’, ‘_’, ‘[’ e ‘]’
Por fim, vou mostrar que temos que tomar CUIDADO com os Wildcard Characters.
Vou criar uma tabela e inserir alguns registros, sendo que cada linha contém um wildcard diferente que iremos filtrar depois.
1 2 3 4 5 6 7 8 9 10 |
CREATE TABLE Teste_Wildcard (Nome VARCHAR(100)) INSERT INTO Teste_Wildcard VALUES ('Eu sou o wildcard "%" e vou ser retornado! Uhhuuu =)'), ('Eu sou o wildcard "_" e vou ser retornado! Uhhuuu =)'), ('Eu sou o wildcard "[" e vou ser retornado! Uhhuuu =)'), ('Eu sou o wildcard "]" e vou ser retornado! Uhhuuu =)') SELECT * FROM Teste_Wildcard |

Quando precisamos buscar algum wildcard character nós iremos utilizar o ESCAPE, que nada mais é do que um caractere que NÃO irá aparecer na string e deve ser utilizado antes do wildcard, mas com ele conseguimos fazer com que um wildcard se comporte como um caractere normal na busca.
Também vamos precisar incluir o ESCAPE ‘caractere’ ao final do LIKE e esse caractere pode ser definido por você!
Então vamos testar!
Caractere ‘%’
O primeiro SELECT irá retornar todas as linhas, pois na verdade o LIKE ‘%%%’ será substituído por LIKE ‘%string vazia = qualquer coisa%’.
Já no segundo SELECT, utilizamos o ESCAPE com o caractere ‘!’ e conseguimos trazer apenas a linha que possui o caractere “%”.
1 2 3 4 5 6 7 8 |
-- CARACTERE "%" SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%%%' SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%!%%' ESCAPE '!' |

Caractere ‘_’
O primeiro SELECT irá retornar todas as linhas, pois na verdade o LIKE ‘%_%’ será substituído por LIKE ‘%qualquer caractere%’.
Já no segundo SELECT, utilizamos o ESCAPE com o caractere ‘?’ e conseguimos trazer apenas a linha que possui o caractere “_”. Repare que dessa vez utilizamos um caractere diferente no ESCAPE.
1 2 3 4 5 6 7 8 |
-- CARACTERE "_" SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%_%' SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%?_%' ESCAPE '?' |

Caractere ‘[’
O primeiro SELECT não irá retornar nenhuma linha!
Já no segundo SELECT, utilizamos o ESCAPE com o caractere ‘+’ e conseguimos trazer apenas a linha que possui o caractere “[”.
1 2 3 4 5 6 7 8 |
-- CARACTERE "[" SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%[%' SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%+[%' ESCAPE '+' |

Caractere ‘]’
Diferente dos exemplos anteriores, nesse caso nós conseguimos filtrar normalmente o caractere “]”, sem precisar incluir o ESCAPE!
1 2 3 4 |
-- CARACTERE "]" SELECT * FROM Teste_Wildcard WHERE Nome LIKE '%]%' |

Conclusão:
Como podemos ver nos exemplos, o operador LIKE pode ter algumas “pegadinhas”.
Portanto, tome cuidado ao escrever uma query que utilize o LIKE, pois você pode deixar de retornar alguns registros que seriam importantes para o seu resultado.
Às vezes, pode ser necessário utilizar o ESCAPE para que possamos buscar um Wildcard Character na string também.
Por fim, a tabela abaixo que está no link da documentação oficial da Microsoft resume bem os conceitos dos Wildcard Characteres.
https://docs.microsoft.com/pt-br/sql/t-sql/language-elements/like-transact-sql?view=sql-server-ver15

Resposta:
Depois de aprender vários conceitos sobre o LIKE, acho que agora podemos responder a nossa pergunta inicial!
Qual a diferença entre LIKE ‘%_TEXTO%’ e ‘%[_]TEXTO%’?
1 2 3 4 5 6 7 |
SELECT * FROM Produto WHERE Nome LIKE '%_TEXTO%' SELECT * FROM Produto WHERE Nome LIKE '%[_]TEXTO%' |
A) Nenhum. Ambos vão retornar sempre o mesmo resultado.
Falso. Como podemos ver, os resultados podem ser diferentes em alguns casos.
B) Ao utilizar ‘%[_]TEXTO%’ será gerado um erro de sintaxe na query.
Falso. Como podemos ver, não gera nenhum erro na query.
C) A opção ‘%[_]TEXTO%’ irá retornar pelo menos os mesmos resultados do que a opção ‘%_TEXTO%’.
Falso. Como podemos ver, acontece exatamente o contrário.
D) A opção ‘%_TEXTO%’ irá retornar pelo menos os mesmos resultados do que a opção ‘%[_]TEXTO%’.
Verdadeiro. Como podemos ver no exemplo, essa é a afirmativa correta!

E) A opção ‘%_TEXTO%’ irá retornar obrigatoriamente o texto “_TEXTO”.
Falso. Como vimos no exemplo, ele retorna alguns registros apenas com o texto “TEXTO” sem o caractere “_”.
Download – Scripts:
Segue abaixo os scripts utilizados nesse post:
Espero que tenha gostado e que isso também possa ser útil no seu dia a dia. Até o próximo post!
Me siga no LinkedIn e YouTube para ficar por dentro das novidades.
Abraço,
Luiz Vitor França Lima
Consultor SQL Server
Pingback: 50 mil acessos no Blog – Luiz Lima