SQL Funções de Texto
Os dados da Loja Aurora estão cheios de texto: nomes de clientes, emails, cidades, telefones, nomes de produtos. E quase nunca do jeito que a Ana precisa mostrar. Ela quer o primeiro nome do cliente para o email de aniversário, o domínio de cada email, o telefone só com números, a cidade e o estado juntos ("Teresina - PI") e o preço com duas casas ("4,90"). Tudo isso se faz no próprio SELECT, com as funções de texto. Nesta aula você vai conhecer as principais e as armadilhas de cada uma, incluindo a mais traiçoeira para quem escreve em português: o upper do SQLite não entende acentos.
- Medir um texto com
length. - Trocar maiúsculas e minúsculas com
upperelower, e o que elas fazem comé,çeã. - Recortar pedaços com
substre achar posições cominstr. - Limpar com
trime trocar trechos comreplace. - Juntar textos com
||, e por que umNULLestraga a junção inteira;concateconcat_ws. - Formatar números e textos com
printf(ouformat):4.9vira4.90.
Os exemplos rodam de verdade no seu navegador, num SQLite com o banco da Loja Aurora, e cada exemplo parte do banco limpo. Texto, em SQL, vai sempre entre aspas simples: 'Ana'.
A ideia: a tesoura, a cola e o carimbo
Pense no balcão da loja com uma ficha de papel de cada cliente. Para preparar as etiquetas de envio, a Ana usa três ferramentas:
- a tesoura, para recortar só um pedaço: o primeiro nome, o DDD do telefone (
substr,trim); - a cola, para juntar pedaços: cidade + " - " + estado (
||,concat); - os carimbos, que mudam a cara do texto sem mudar o conteúdo: tudo em maiúsculas, o preço com duas casas (
upper,printf).
As funções de texto são essas ferramentas. Um detalhe importante: elas não mudam a tabela. Um SELECT upper(nome) FROM clientes mostra os nomes em maiúsculas, mas os nomes guardados continuam como estavam. Só um UPDATE (aula UPDATE) muda o que está guardado.
Toda função tem o mesmo molde: o nome, e entre parênteses o que ela recebe (os argumentos), separados por vírgula: substr(nome, 1, 3).
1. length: quantas letras
SELECT nome, length(nome) AS letras FROM clientes ORDER BY letras DESC LIMIT 3;
length ("comprimento") conta os caracteres do texto, contando os espaços. O nome mais comprido da loja é "Gustavo Henrique Prado", com 22. As letras acentuadas contam como uma letra cada, como deveria ser:
SELECT nome,
length(nome) AS letras,
octet_length(nome) AS bytes
FROM clientes
WHERE id IN (3, 5);
"Conceição Prado" tem 15 letras, mas ocupa 17 bytes no arquivo: o ç e o ã gastam 2 bytes cada (é assim que o formato UTF-8 guarda letras acentuadas). A octet_length ("comprimento em octetos", ou bytes) mostra isso. Para contar letras, use sempre a length.
| Escrita | Resultado | Por quê |
|---|---|---|
length('Ana') | 3 | Três letras |
length('') | 0 | Texto vazio |
length(NULL) | NULL | Sem valor, sem tamanho (os clientes sem email têm length(email) NULL) |
length(12.5) | 4 | Um número é medido como texto: '12.5' |
2. upper e lower: maiúsculas e minúsculas
upper ("de cima", as letras maiúsculas) e lower ("de baixo", as minúsculas) trocam a caixa das letras. Com nomes sem acento, tudo certo:
SELECT upper('Ana Beatriz Sousa') AS maiusculas,
lower('Ana Beatriz Sousa') AS minusculas;
Agora com os nomes acentuados da loja:
SELECT nome, upper(nome) AS maiusculas, lower(nome) AS minusculas FROM clientes WHERE id IN (1, 5, 9);
Olhe com atenção: JOSé RIBAMAR SILVA, CONCEIçãO PRADO, ANTôNIO CARLOS NEVES. As letras acentuadas não mudaram. O upper e o lower do SQLite só sabem trocar as 26 letras do alfabeto inglês, de a a z (o conjunto ASCII). O é, o ç, o ã e o ô passam direto, do jeito que estavam. É uma escolha do SQLite, para ficar pequeno: tratar maiúsculas e minúsculas de todas as línguas do mundo exige tabelas grandes.
- Etiquetas em maiúsculas com acento saem misturadas (
CONCEIçãO). - Buscas que ignoram maiúsculas.
WHERE upper(nome) LIKE '%CONCEIÇÃO%'não acha a Conceição, porqueupper('Conceição')é'CONCEIçãO', e não'CONCEIÇÃO'. Pelo mesmo motivo, oLIKE(aula LIKE) ignora maiúsculas só nas letras sem acento:'Ana' LIKE 'ana'é verdadeiro, mas'Água' LIKE 'água'é falso.
O que fazer: para emails e códigos (que não têm acento), lower funciona perfeitamente. Para nomes, guarde os dados já bem escritos e busque como eles estão guardados, ou deixe as maiúsculas para o programa que mostra os dados (PHP, Python, JavaScript sabem lidar com acentos). Existe também uma extensão do SQLite, a ICU, que ensina acentos ao upper e ao lower; ela não vem no SQLite padrão nem no editor do guia.
SELECT 'Ana' LIKE 'ana' AS sem_acento,
'Água' LIKE 'água' AS com_acento,
upper('josé') = 'JOSÉ' AS upper_com_acento,
lower('ANA.BEATRIZ@EXEMPLO.COM.BR') AS email_minusculo;
Os resultados 1 e 0 são o "verdadeiro" e o "falso" do SQLite. O email ficou certinho em minúsculas: só tinha letras sem acento.
3. substr: recortar um pedaço
substr (de substring, "pedaço do texto") recorta um trecho. Ela recebe o texto, a posição onde começa e, se quiser, quantos caracteres levar. A primeira letra é a posição 1:
SELECT substr('Ana Beatriz Sousa', 1, 3) AS do_1_leva_3,
substr('Ana Beatriz Sousa', 5, 7) AS do_5_leva_7,
substr('Ana Beatriz Sousa', 5) AS do_5_ate_o_fim,
substr('Ana Beatriz Sousa', -5) AS ultimas_5;
| Posição | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Letra | A | n | a | ␣ | B | e | a | t | r | i | z | ␣ | S | o | u | s | a |
(O ␣ marca os espaços: eles também ocupam uma posição.)
- substr(texto, 1, 3)
- Começa na posição 1 e leva 3:
Ana. - substr(texto, 5, 7)
- Começa na posição 5 (o
B) e leva 7:Beatriz. - substr(texto, 5)
- Sem o terceiro argumento, vai até o fim:
Beatriz Sousa. - substr(texto, -5)
- Posição negativa conta do fim para o começo: as 5 últimas,
Sousa.
O SQLite também aceita o nome substring, do SQL padrão, com os mesmos argumentos.
instr: onde está?
Para recortar o primeiro nome, a posição do corte muda de cliente para cliente: "Ana" tem 3 letras, "Carlos" tem 6. A instr (de in string, "no texto") diz em que posição um trecho aparece pela primeira vez, ou 0 se não aparece:
SELECT nome,
instr(nome, ' ') AS posicao_do_espaco,
substr(nome, 1, instr(nome, ' ') - 1) AS primeiro_nome
FROM clientes
WHERE id <= 4;
Em "José Ribamar Silva", o primeiro espaço está na posição 5. O primeiro nome vai da posição 1 e leva 5 − 1 = 4 letras: "José". O - 1 é para não levar o espaço junto. O mesmo truque separa as duas partes de um email:
SELECT email,
substr(email, 1, instr(email, '@') - 1) AS usuario,
substr(email, instr(email, '@') + 1) AS dominio
FROM clientes
WHERE id <= 3;
O usuário é tudo antes do @ (até a posição dele − 1); o domínio é tudo depois (da posição dele + 1 até o fim).
Experimente: a Ana vai mandar um email de aniversário que começa com "Olá, José!". Ela precisa só do primeiro nome de cada cliente. Troque o nome do SELECT por um substr com instr que recorte até antes do primeiro espaço, mantendo o apelido primeiro_nome.
SELECT nome AS primeiro_nome FROM clientes;
SELECT substr(nome, 1, instr(nome, ' ') - 1) AS primeiro_nome FROM clientes;
4. trim e replace: limpar e trocar
trim: tirar as sobras das pontas
Quem digita um cadastro às vezes deixa espaços sobrando no começo ou no fim: ' Ana '. Para o banco, 'Ana' e 'Ana ' são textos diferentes, e uma busca por 'Ana' não acha o segundo. A trim ("aparar") tira os espaços das duas pontas; ltrim só da esquerda (left) e rtrim só da direita (right). As barras | no exemplo estão lá só para você enxergar onde o texto acaba:
SELECT '|' || trim(' Ana ') || '|' AS com_trim,
'|' || ltrim(' Ana ') || '|' AS com_ltrim,
'|' || rtrim(' Ana ') || '|' AS com_rtrim,
trim('--Ana--', '-') AS outro_caractere;
Com um segundo argumento, a trim tira outros caracteres das pontas: trim('--Ana--', '-') tira os hífens. Ela nunca mexe no meio do texto: trim('Ana Lima') mantém o espaço entre os nomes.
replace: trocar um trecho por outro
replace ("substituir") troca todas as vezes que um trecho aparece. Ela recebe o texto, o que procurar e o que pôr no lugar:
SELECT replace('Caneta Esferográfica Azul', 'Azul', 'Preta') AS outra_cor,
replace('banana', 'a', 'o') AS todas_as_vezes,
replace('(86) 99821-4455', '-', '') AS sem_hifen;
Para deixar o telefone só com números, é preciso tirar quatro coisas: parênteses, espaço e hífen. Uma replace dentro da outra, de dentro para fora:
SELECT nome, telefone,
replace(replace(replace(replace(telefone, '(', ''), ')', ''), ' ', ''), '-', '') AS so_numeros
FROM fornecedores;
Leia de dentro para fora: a replace mais de dentro tira o (; a de fora dela tira o ); depois o espaço; por último o hífen. Os telefones de Portugal e da Argentina ficaram com o + do código do país, porque ele não estava na lista.
5. Juntar textos: ||, concat e concat_ws
No SQL padrão, quem junta (ou concatena) textos é o operador ||, duas barras verticais. Ele cola o da esquerda com o da direita, sem pôr nada no meio; os espaços e separadores são por sua conta:
SELECT nome,
cidade || ' - ' || estado AS local
FROM clientes
WHERE id <= 3;
Três pedaços colados: a cidade, o texto ' - ' (espaço, hífen, espaço) e o estado. Números também podem entrar na junção, e viram texto: 'Total: ' || 30.94 dá Total: 30.94.
O NULL estraga a junção inteira
Agora com os fornecedores. Dois deles são estrangeiros e estão com estado NULL:
SELECT nome, cidade, estado,
cidade || ' - ' || estado AS local
FROM fornecedores;
Para a Lusitana Comércio (Porto) e a Pampa Sur (Buenos Aires), o local inteiro virou NULL, e a cidade, que existia, sumiu junto. É a regra do NULL (aula O Valor NULL): qualquer conta com um valor desconhecido dá desconhecido, e juntar textos é uma conta. Três jeitos de consertar:
SELECT nome,
cidade || ' - ' || coalesce(estado, pais) AS com_coalesce,
concat(cidade, ' - ', estado) AS com_concat,
concat_ws(' - ', cidade, estado) AS com_concat_ws
FROM fornecedores;
- coalesce(estado, pais)
- Usa o estado; se ele for NULL, usa o país (aula IFNULL e COALESCE). Resultado:
Porto - Portugal. - concat(a, b, c, …)
- Junta todos os argumentos, tratando NULL como texto vazio. Não some com a cidade, mas sobra o separador:
Porto -, com o hífen pendurado. - concat_ws(separador, a, b, …)
- "Concat with separator", com separador. O primeiro argumento é o separador, posto entre os outros, e os NULL são pulados junto com o seu separador:
Porto, limpinho.
Missão: a lista de fornecedores com o local perdeu Porto e Buenos Aires, porque o estado deles é NULL. Conserte a coluna local para que nenhuma cidade suma. Pode ser com coalesce, concat ou concat_ws: você escolhe.
SELECT nome,
cidade || ' - ' || estado AS local
FROM fornecedores;
SELECT nome,
concat_ws(' - ', cidade, estado) AS local
FROM fornecedores;
6. printf e format: carimbar números e textos
O SQLite escreve os números do jeito mais curto: o marca-texto custa 4.9, e não 4.90. Para uma etiqueta de preço, isso é feio. A printf ("imprima formatado", um nome que vem da linguagem C) recebe um molde e os valores que entram nele. O SQLite também a chama de format; as duas são a mesma função.
SELECT nome, preco,
printf('%.2f', preco) AS duas_casas,
format('R$ %.2f', preco) AS com_moeda,
replace(printf('%.2f', preco), '.', ',') AS jeito_brasileiro
FROM produtos
WHERE id IN (1, 4, 9, 14);
- '%.2f'
- Um número com 2 casas depois do ponto (
fde float, número com vírgula).4.9vira4.90;99.0vira99.00. - 'R$ %.2f'
- O que está fora do código é copiado como está: o
R$fica na frente. - replace(…, '.', ',')
- A
printfusa ponto. Para o formato brasileiro, troque o ponto pela vírgula.
O resultado da printf é texto, pronto para mostrar. Não use esse texto para fazer contas nem para ordenar: para isso, use o número original (ou a round, da aula Funções Numéricas).
Os códigos da printf
SELECT printf('%05d', 42) AS cinco_digitos,
printf('%s tem %d anos', 'Ana', 30) AS frase,
printf('%d%%', 15) AS porcentagem,
printf('[%-6s]', 'Ana') AS alinhado_esquerda,
printf('[%6s]', 'Ana') AS alinhado_direita;
| Código | O que põe no lugar | Exemplo |
|---|---|---|
%s | Um texto (string) | printf('Olá, %s!', 'Ana') → Olá, Ana! |
%d | Um número inteiro (decimal) | printf('%d itens', 3) → 3 itens |
%.2f | Número com 2 casas (troque o 2 por quantas quiser) | printf('%.1f', 4.25) → 4.3 |
%05d | Inteiro com 5 dígitos, completando com zeros à esquerda | printf('%05d', 42) → 00042 |
%6s / %-6s | Texto ocupando 6 espaços, alinhado à direita / à esquerda | [ Ana] / [Ana ] |
%% | Um % de verdade | printf('%d%%', 15) → 15% |
Cada código pega o próximo valor da lista, na ordem: em printf('%s tem %d anos', 'Ana', 30), o %s pega 'Ana' e o %d pega 30.
7. Formas diferentes de fazer
Muitas tarefas de texto têm mais de uma solução. Para "cidade - estado, sem perder ninguém":
| Forma | Com estado NULL dá | Quando usar |
|---|---|---|
cidade || ' - ' || estado | NULL (perde tudo) | Quando você tem certeza de que nada é NULL (ex.: colunas NOT NULL). É o SQL padrão. |
cidade || ' - ' || coalesce(estado, '?') | Porto - ? | Quando quer um valor no lugar do NULL. |
concat(cidade, ' - ', estado) | Porto - | Para juntar sem perder nada; existe também no MySQL, PostgreSQL e SQL Server. |
concat_ws(' - ', cidade, estado) | Porto | Para listas com separador (endereço, nome completo), pulando o que faltar. |
printf('%s - %s', cidade, estado) | Porto - | Quando a junção também precisa formatar números. |
E para "o primeiro nome": substr(nome, 1, instr(nome, ' ') - 1) funciona para todo nome com espaço. Para nomes de uma palavra só, veja o primeiro caso de Quando dá errado.
Quando dá errado
SELECT instr('Maria', ' ') AS posicao,
substr('Maria', 1, instr('Maria', ' ') - 1) AS primeiro_nome;
O que aconteceu: o primeiro nome saiu vazio. "Maria" não tem espaço, a instr devolveu 0, e 0 - 1 é -1: pedir −1 letras dá nada. Todos os clientes da loja têm sobrenome, mas um cadastro novo pode não ter.
Como consertar: acrescente um espaço no fim antes de procurar, para sempre achar um: substr(nome, 1, instr(nome || ' ', ' ') - 1).
+
SELECT 'Ana' + ' Lima' AS com_mais,
'Ana' || ' Lima' AS com_barras;
O que aconteceu: 0. No SQLite, + é sempre soma de números; ele tentou transformar 'Ana' e ' Lima' em números, não conseguiu, usou 0 para cada um e somou: 0. Sem erro. (No SQL Server, + junta textos; veja "Nos outros bancos".)
Como consertar: no SQLite, junte com || ou concat.
SELECT substr('Ana Beatriz', 0, 3) AS comecando_do_zero,
substr('Ana Beatriz', 1, 3) AS comecando_do_um;
O que aconteceu: veio só An. Quem programa em linguagens como Python e JavaScript está acostumado a contar do zero, mas no SQL a primeira letra é a posição 1. A posição 0 fica "antes" do texto e gasta uma das 3 letras pedidas.
Como consertar: comece do 1.
SELECT nome FROM clientes WHERE cidade = "Teresina";
O que aconteceu: no such column: "Teresina" - should this be a string literal in single-quotes?, "não existe a coluna "Teresina"; deveria ser um texto entre aspas simples?". Em SQL, aspas duplas são para nomes (de colunas e tabelas). Texto é sempre com aspas simples.
Como consertar: WHERE cidade = 'Teresina'.
O fornecedor 2 se chama Loja D'Água. O apóstrofo é a mesma aspa simples que fecha o texto, então 'Loja D'Água' termina no D, e o resto vira lixo de sintaxe:
SELECT nome, cidade FROM fornecedores WHERE nome = 'Loja D'Água';
O que aconteceu: near "Água": syntax error, "erro de sintaxe perto de Água": o pedaço que ficou fora das aspas.
Como consertar: dentro de um texto, um apóstrofo se escreve com duas aspas simples seguidas: 'Loja D''Água'.
SELECT nome, cidade FROM fornecedores WHERE nome = 'Loja D''Água';
SELECT LEFT(nome, 3) AS inicio FROM clientes;
O que aconteceu: no such function: LEFT. O LEFT ("esquerda") existe no MySQL e no SQL Server, mas não no SQLite.
Como consertar: substr(nome, 1, 3). Para o RIGHT, substr(nome, -3).
Os nomes e alguns comportamentos mudam bastante de um banco para outro. Trechos ilustrativos, que não rodam no SQLite:
| Tarefa | SQLite | PostgreSQL | MySQL | SQL Server |
|---|---|---|---|---|
| Juntar | a || b, concat | a || b, concat | CONCAT(a, b) (o || é "ou" lógico, a não ser num modo especial) | a + b, CONCAT(a, b) |
| Tamanho em letras | length | length, char_length | CHAR_LENGTH (o LENGTH conta bytes) | LEN (ignora espaços no fim) |
| Maiúsculas com acento | Não (só A–Z) | Sim | Sim | Sim |
| Começo do texto | substr(s, 1, 3) | left(s, 3), substr | LEFT(s, 3) | LEFT(s, 3), SUBSTRING |
| Posição | instr(s, t) | strpos(s, t), position(t IN s) | INSTR(s, t), LOCATE(t, s) | CHARINDEX(t, s) |
O caso do MySQL merece atenção: SELECT 'a' || 'b', que no SQLite dá ab, no MySQL (no modo padrão) é uma conta de "ou" lógico e dá 0. Use CONCAT quando o mesmo SQL tiver de rodar nos dois. E o LENGTH('Conceição') do MySQL dá 11 (bytes), e não 9.
Referência rápida
| Função | O que faz | Exemplo → resultado |
|---|---|---|
length(s) | Número de caracteres | length('Conceição') → 9 |
octet_length(s) | Número de bytes | octet_length('Conceição') → 11 |
upper(s) / lower(s) | Maiúsculas / minúsculas (só A–Z!) | upper('josé') → JOSé |
substr(s, início, qtd) | Recorta (a 1ª letra é a posição 1; negativo conta do fim) | substr('Aurora', 1, 3) → Aur |
instr(s, t) | Posição da 1ª vez que t aparece; 0 se não aparece | instr('ana@x', '@') → 4 |
trim(s), ltrim, rtrim | Tira espaços (ou os caracteres dados) das pontas | trim(' Ana ') → Ana |
replace(s, de, para) | Troca todas as ocorrências | replace('a-b-c', '-', '') → abc |
a || b | Junta (com NULL, dá NULL) | 'Ana' || ' Lima' → Ana Lima |
concat(a, b, …) | Junta, tratando NULL como vazio | concat('Ana', NULL) → Ana |
concat_ws(sep, a, b, …) | Junta com separador, pulando os NULL | concat_ws(', ', 'a', NULL, 'b') → a, b |
printf(molde, …) = format | Formata (%s, %d, %.2f, %05d, %%) | printf('%.2f', 4.9) → 4.90 |
Exercícios
1. Os três primeiros caracteres
Complete para pegar as 3 primeiras letras do nome:
2. Juntar com separador
Complete o operador que junta textos no SQL padrão:
3. O que upper('Conceição') devolve no SQLite?
4. O fornecedor Pampa Sur tem estado NULL. O que cidade || ' - ' || estado mostra para ele?
5. Qual expressão mostra o preço 4.9 como 4.90?
6. Quanto vale instr('ana.beatriz@exemplo.com.br', '@')?
Missão final: as etiquetas da papelaria
Missão: a papelaria (categoria 1) vai ganhar etiquetas novas. Para cada produto dela, mostre três colunas: codigo, a letra P seguida do id com 3 dígitos (o produto 4 vira P004); produto, o nome; e preco_br, o preço com duas casas e vírgula (4,90).
SELECT id, nome, preco FROM produtos WHERE categoria_id = 1;
SELECT 'P' || printf('%03d', id) AS codigo,
nome AS produto,
replace(printf('%.2f', preco), '.', ',') AS preco_br
FROM produtos
WHERE categoria_id = 1;
Outra resposta certa para o código: printf('P%03d', id), com o P dentro do molde.
Resumo
- Funções de texto mudam o que o
SELECTmostra, nunca o que está guardado. lengthconta caracteres (com acento, 1 cada);octet_lengthconta bytes.upperelowerno SQLite só trocam as letras A–Z:upper('Conceição')dáCONCEIçãO. Use-as sem medo em emails e códigos.substr(s, início, qtd)recorta, contando do 1;instr(s, t)acha a posição (0 se não acha). Juntas, separam primeiro nome, usuário e domínio do email.trimlimpa as pontas;replacetroca todas as ocorrências.||junta textos, mas um NULL derruba tudo;concattrata NULL como vazio econcat_wspula o NULL junto com o separador.+não junta textos no SQLite.printf(ouformat) carimba:'%.2f'para duas casas,'%05d'para zeros à esquerda. O resultado é texto, para mostrar.