Por que funções de texto são essenciais em análises do dia a dia
Em bases operacionais e integrações entre sistemas, campos de texto costumam ser a principal fonte de inconsistência: nomes digitados com variações, espaços extras, letras maiúsculas e minúsculas misturadas, acentos, pontuação, formatos diferentes de telefone e documento, além de descrições longas que precisam virar categorias. Em relatórios, essas variações geram segmentações erradas (o mesmo cliente aparece como dois), dificultam filtros e aumentam o trabalho manual de “arrumar no Excel”.
Funções de texto em SQL permitem padronizar, limpar e categorizar diretamente na consulta, criando saídas consistentes para dashboards, exportações e rotinas de qualidade de dados. A ideia não é “embelezar” o texto, mas reduzir ruído e transformar strings em chaves e grupos confiáveis.
Tipos de problemas comuns em campos de texto
- Variação de caixa: “SP”, “sp”, “Sp”.
- Espaços invisíveis: “Maria ” (com espaço no fim), “ Maria” (no início), múltiplos espaços no meio.
- Pontuação e caracteres especiais: “(11) 99999-8888” vs “11999998888”.
- Acentos: “São Paulo” vs “Sao Paulo”.
- Campos compostos: “Produto - Categoria - Subcategoria” em uma única coluna.
- Descrições livres: motivo de cancelamento, observações, comentários.
- Dados sem padrão: e-mails com espaços, domínios com caixa variada, URLs com parâmetros.
Funções de texto mais usadas para padronização
1) UPPER e LOWER: padronização de caixa
Padronizar caixa é uma das formas mais simples de evitar duplicidade em agrupamentos e comparações. Em geral, usa-se UPPER() ou LOWER() para garantir que “sp” e “SP” sejam tratados como o mesmo valor.
SELECT UPPER(estado) AS estado_padronizado, COUNT(*) AS qtd_clientes FROM clientes GROUP BY UPPER(estado);Quando usar: ao agrupar, comparar, deduplicar e criar chaves textuais. Atenção: isso não resolve acentos e caracteres especiais, apenas caixa.
2) TRIM, LTRIM e RTRIM: remoção de espaços
Espaços extras são invisíveis, mas quebram comparações e joins por texto. TRIM() remove espaços do início e do fim. Alguns bancos também oferecem LTRIM() e RTRIM().
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
SELECT TRIM(nome) AS nome_limpo FROM clientes;Uma prática comum é combinar TRIM com UPPER para padronização básica:
SELECT UPPER(TRIM(nome)) AS nome_padronizado FROM clientes;3) REPLACE: substituição direta
REPLACE(texto, alvo, substituto) troca ocorrências de um trecho por outro. É útil para remover pontuação, normalizar separadores e limpar caracteres recorrentes.
SELECT REPLACE(cpf, '.', '') AS cpf_sem_ponto FROM clientes;Para remover múltiplos caracteres, você pode encadear:
SELECT REPLACE(REPLACE(REPLACE(telefone, '(', ''), ')', ''), '-', '') AS telefone_numeros FROM contatos;Quando usar: limpeza simples e previsível. Para padrões mais complexos, funções com regex (quando disponíveis) costumam ser melhores.
4) CONCAT e operador de concatenação: construção de chaves e rótulos
Em relatórios, é comum criar rótulos como “Cidade/UF” ou chaves compostas. A função pode ser CONCAT() ou o operador ||, dependendo do banco.
SELECT CONCAT(TRIM(cidade), '/', UPPER(TRIM(estado))) AS cidade_uf FROM enderecos;Boa prática: sempre padronize os componentes antes de concatenar, para evitar chaves inconsistentes.
5) LENGTH/CHAR_LENGTH: validações e regras
Medir o tamanho do texto ajuda a detectar valores fora do padrão (ex.: CEP com tamanho diferente, telefone curto demais, códigos truncados).
SELECT cep FROM enderecos WHERE CHAR_LENGTH(TRIM(cep)) <> 8;Isso é útil tanto para auditoria quanto para criar regras de categorização (ex.: identificar se um identificador é CPF ou CNPJ pelo tamanho).
Funções para extração e recorte de texto
1) SUBSTRING: pegar parte do texto
SUBSTRING (ou SUBSTR) extrai um trecho a partir de uma posição, com um tamanho opcional. É útil quando o padrão é fixo (ex.: código com prefixo).
SELECT SUBSTRING(codigo_produto FROM 1 FOR 3) AS prefixo, COUNT(*) FROM produtos GROUP BY SUBSTRING(codigo_produto FROM 1 FOR 3);Exemplo de uso: prefixos que indicam linha de produto, ou primeiros dígitos de um CEP para agrupar por região.
2) LEFT e RIGHT: recortes simples
Alguns bancos oferecem LEFT(texto, n) e RIGHT(texto, n) para pegar os primeiros/últimos caracteres.
SELECT LEFT(TRIM(cep), 5) AS cep_base FROM enderecos;3) POSITION/INSTR: localizar separadores
Quando o texto tem separadores (ex.: “categoria - subcategoria”), você pode localizar a posição do separador e recortar com SUBSTRING. A função pode ser POSITION ou INSTR, dependendo do banco.
SELECT SUBSTRING(descricao FROM 1 FOR POSITION('-' IN descricao) - 1) AS categoria_bruta FROM produtos;Esse tipo de lógica é útil para transformar descrições semi-estruturadas em colunas mais analíticas.
Categorização com CASE + funções de texto
Categorizar significa transformar texto livre ou códigos variados em grupos padronizados (ex.: canal de venda, tipo de cliente, motivo de contato). O recurso central é CASE, combinado com funções de texto para reduzir variações.
Exemplo: categorizar canal a partir de origem com variações
Suponha um campo origem com valores como “Instagram”, “insta”, “IG Ads”, “Google Ads”, “g ads”, “Indicação”, “indicacao”. Você pode padronizar e mapear:
SELECT CASE WHEN LOWER(TRIM(origem)) IN ('instagram', 'insta', 'ig ads', 'igads') THEN 'Instagram' WHEN LOWER(TRIM(origem)) IN ('google ads', 'g ads', 'gads') THEN 'Google Ads' WHEN LOWER(TRIM(origem)) IN ('indicação', 'indicacao', 'indicacao ') THEN 'Indicação' WHEN origem IS NULL OR TRIM(origem) = '' THEN 'Não informado' ELSE 'Outros' END AS canal_padronizado, COUNT(*) AS qtd FROM leads GROUP BY CASE WHEN LOWER(TRIM(origem)) IN ('instagram', 'insta', 'ig ads', 'igads') THEN 'Instagram' WHEN LOWER(TRIM(origem)) IN ('google ads', 'g ads', 'gads') THEN 'Google Ads' WHEN LOWER(TRIM(origem)) IN ('indicação', 'indicacao', 'indicacao ') THEN 'Indicação' WHEN origem IS NULL OR TRIM(origem) = '' THEN 'Não informado' ELSE 'Outros' END;Observações práticas: (1) aplique TRIM e LOWER antes de comparar; (2) trate nulos e strings vazias; (3) mantenha uma categoria “Outros” para capturar novos valores.
Passo a passo prático: limpar e padronizar telefone e e-mail para uso em relatórios
Objetivo: gerar colunas padronizadas para facilitar deduplicação, contato e segmentação. Exemplo com uma tabela contatos contendo telefone e email como texto livre.
Passo 1: remover espaços e padronizar caixa do e-mail
E-mails devem ser comparados de forma consistente. Em geral, padronizar para minúsculas e remover espaços no início/fim já resolve boa parte.
SELECT id_contato, LOWER(TRIM(email)) AS email_padronizado FROM contatos;Se o problema for espaço no meio (ex.: “joao @empresa.com”), você pode remover espaços com REPLACE:
SELECT id_contato, LOWER(REPLACE(TRIM(email), ' ', '')) AS email_padronizado FROM contatos;Passo 2: manter apenas números no telefone (limpeza básica)
Telefones vêm com parênteses, traços e espaços. Uma limpeza básica encadeia REPLACE para remover caracteres comuns.
SELECT id_contato, REPLACE(REPLACE(REPLACE(REPLACE(TRIM(telefone), ' ', ''), '(', ''), ')', ''), '-', '') AS telefone_numeros FROM contatos;Se houver “+55”, você pode remover também:
SELECT id_contato, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(TRIM(telefone), ' ', ''), '(', ''), ')', ''), '-', ''), '+', '') AS telefone_numeros FROM contatos;Passo 3: validar tamanho e criar uma coluna de status
Após limpar, valide o tamanho para identificar registros suspeitos. No Brasil, celulares costumam ter 11 dígitos com DDD. Você pode criar um status simples:
SELECT id_contato, telefone, REPLACE(REPLACE(REPLACE(REPLACE(TRIM(telefone), ' ', ''), '(', ''), ')', ''), '-', '') AS telefone_numeros, CASE WHEN telefone IS NULL OR TRIM(telefone) = '' THEN 'Vazio' WHEN CHAR_LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(TRIM(telefone), ' ', ''), '(', ''), ')', ''), '-', '')) IN (10, 11) THEN 'OK' ELSE 'Tamanho fora do padrão' END AS status_telefone FROM contatos;Esse passo é útil para criar uma lista de correção, priorizar limpeza e evitar usar telefones inválidos em campanhas.
Normalização de texto para deduplicação (chave “limpa”)
Deduplicar registros por nome, empresa ou endereço é difícil porque pequenas variações geram chaves diferentes. Uma estratégia prática é criar uma “chave normalizada”: caixa padronizada, espaços ajustados e remoção de pontuação mais comum.
Exemplo: chave de empresa
SELECT id_cliente, razao_social, UPPER(TRIM(razao_social)) AS razao_upper, REPLACE(REPLACE(UPPER(TRIM(razao_social)), '.', ''), ',', '') AS razao_sem_pontuacao FROM clientes;Você pode ir além removendo “LTDA”, “ME”, “EPP” para aproximar nomes, mas isso exige cuidado para não unir empresas diferentes. Quando fizer esse tipo de regra, mantenha a coluna original e a coluna normalizada separadas, e valide com amostras.
Busca por padrões: LIKE e funções de texto
Para categorização e auditoria, é comum buscar padrões em descrições (ex.: identificar “frete”, “desconto”, “chargeback”). O operador LIKE funciona bem para padrões simples, especialmente quando combinado com LOWER para evitar problemas de caixa.
Exemplo: classificar motivo de estorno por palavras-chave
SELECT id_transacao, motivo, CASE WHEN motivo IS NULL OR TRIM(motivo) = '' THEN 'Não informado' WHEN LOWER(motivo) LIKE '%fraude%' OR LOWER(motivo) LIKE '%chargeback%' THEN 'Fraude/Chargeback' WHEN LOWER(motivo) LIKE '%duplic%' THEN 'Cobrança duplicada' WHEN LOWER(motivo) LIKE '%atras%' OR LOWER(motivo) LIKE '%entrega%' THEN 'Entrega/Atraso' ELSE 'Outros' END AS categoria_motivo FROM estornos;Boa prática: use padrões curtos e robustos (ex.: “duplic” pega “duplicado”, “duplicidade”). Evite padrões longos demais que falham com pequenas variações.
Dividir campos compostos em colunas analíticas
Às vezes um campo contém múltiplas informações, como “Departamento > Categoria > Subcategoria”. Para análise, você quer cada nível em uma coluna. Sem funções específicas de split, dá para resolver com POSITION + SUBSTRING quando o separador é consistente.
Exemplo: extrair o primeiro nível antes do separador
SELECT id_produto, hierarquia, TRIM(SUBSTRING(hierarquia FROM 1 FOR POSITION('>' IN hierarquia) - 1)) AS departamento FROM produtos;Se o banco tiver função de split (varia por dialeto), ela simplifica bastante. Mesmo assim, o princípio é o mesmo: identificar separador, recortar, aplicar TRIM e padronizar caixa.
Tratamento de acentos e caracteres especiais (quando disponível)
Remover acentos pode ser importante para comparar “São Paulo” e “Sao Paulo” como iguais, especialmente em integrações. Nem todo banco tem uma função nativa universal para isso. Alguns oferecem funções de transliteração/normalização; em outros, isso é feito via extensões ou tabelas de mapeamento.
Abordagem prática quando não há função pronta: (1) padronize caixa e espaços; (2) crie uma tabela de referência com a forma “oficial” e possíveis variações; (3) faça o mapeamento por comparação padronizada. Exemplo conceitual de mapeamento com uma tabela map_cidades contendo cidade_variacao e cidade_oficial:
SELECT e.id_endereco, e.cidade, m.cidade_oficial FROM enderecos e LEFT JOIN map_cidades m ON UPPER(TRIM(e.cidade)) = UPPER(TRIM(m.cidade_variacao));Isso evita depender de uma função específica do banco e torna a regra auditável (você enxerga quais variações estão sendo mapeadas).
Checklist prático para aplicar funções de texto com segurança
- Preserve o original: selecione a coluna original e a coluna limpa lado a lado para validação.
- Padronize antes de comparar: aplique
TRIM+LOWER/UPPERantes deCASE,LIKEe agrupamentos. - Trate vazio e nulo: diferencie
NULLde string vazia ('') quando necessário. - Evite regras agressivas sem validação: remover sufixos (“LTDA”) e palavras pode causar colisões.
- Crie colunas de status: “OK”, “Inválido”, “Fora do padrão” acelera auditoria e correção.
- Documente mapeamentos: para categorização, prefira tabelas de referência quando a lista cresce.
- Teste com amostras reais: pegue os 50 valores mais frequentes e os 50 mais estranhos para validar a regra.
Exercício guiado: padronizar e categorizar um campo de produto para relatório
Cenário: a coluna nome_produto vem com variações como “Camisa Polo - Azul”, “camisa polo azul”, “Camisa-Polo/Azul”, “CAMISA POLO (AZUL)”. Você quer: (1) uma versão padronizada para deduplicar; (2) uma categoria simples (ex.: “Camisa Polo”, “Outros”).
Passo 1: criar uma versão padronizada
Uma limpeza inicial remove espaços nas bordas, padroniza caixa e troca alguns separadores por espaço. Depois, você pode reduzir múltiplos separadores para um formato mais uniforme.
SELECT id_produto, nome_produto, UPPER(TRIM(nome_produto)) AS nome_upper, REPLACE(REPLACE(REPLACE(UPPER(TRIM(nome_produto)), '-', ' '), '/', ' '), '(', ' ') AS nome_quase_limpo FROM produtos;Dependendo do banco, você pode precisar remover também “)” e duplicidades de espaço. Mesmo sem uma função específica para “colapsar espaços”, só o fato de padronizar separadores já melhora bastante a consistência.
Passo 2: categorizar por padrão de texto
Agora, use LIKE em cima de uma versão normalizada (por exemplo, LOWER(TRIM(...))) para identificar a categoria.
SELECT id_produto, nome_produto, CASE WHEN LOWER(nome_produto) LIKE '%camisa%polo%' THEN 'Camisa Polo' WHEN LOWER(nome_produto) LIKE '%calca%jeans%' OR LOWER(nome_produto) LIKE '%jeans%' THEN 'Calça Jeans' ELSE 'Outros' END AS categoria FROM produtos;Se você perceber que a categoria está capturando itens indevidos, refine os padrões (por exemplo, exigindo duas palavras-chave) ou crie uma tabela de mapeamento por SKU/código quando houver identificadores mais confiáveis do que o nome.