O TRANSLATE recebe uma string e dois mapas de caracteres equivalentes: cada caractere do primeiro conjunto e trocado pelo da mesma posicao no segundo. E uma operacao caractere a caractere, nao de substrings, e e exatamente isso que a separa do REPLACE. Use-o quando precisar limpar ou normalizar caracteres individuais -- separadores, pontuacao, letras parecidas -- em uma unica passada, sem chamadas aninhadas nem expressoes regulares.
Sintaxe basica
A assinatura e simples: TRANSLATE(text, from_set, to_set). O caractere from_set[i] vira to_set[i].
SELECT TRANSLATE('abc', 'abc', 'xyz');
SELECT TRANSLATE('a-b-c', 'abc', 'xyz');
Os hifens ficam no lugar: nao estao no from_set, entao nao sao tocados. O TRANSLATE processa cada caractere de forma independente e em uma unica passada.
- A correspondencia e estritamente posicional: o primeiro com o primeiro, o segundo com o segundo.
- Caracteres fora do
from_set sao copiados sem alteracao.
- Maiusculas importam:
a e A sao caracteres diferentes.
Apagar caracteres: quando to_set e mais curto
Se um caractere nao tem par no segundo conjunto, ele e removido. Esse e o uso mais pratico do TRANSLATE.
SELECT id, TRANSLATE(name, ' .,()-+', '') AS cleaned
FROM users;
Aqui o to_set esta vazio, entao cada separador listado simplesmente some. Um caso comum e tirar a formatacao de telefones ou SKUs:
SELECT TRANSLATE('+1 (555) 123-45-67', ' ()-+', '');
O mesmo truque arruma os status de pedido antes de um export:
SELECT id, TRANSLATE(status, '_', ' ') AS label
FROM orders;
Transliteracao em uma passada
O TRANSLATE e otimo para criar valores tipo slug ou normalizar caracteres. Mapeie cada caractere "perigoso" para um seguro em uma unica chamada:
SELECT id,
TRANSLATE(LOWER(name), ' /\\.', '----') AS slug_part
FROM employees;
Leia esses literais ao pe da letra. O from_set e escrito ' /\\.': dentro de aspas simples o PostgreSQL le \\ como dois caracteres de barra invertida, entao o conjunto tem cinco caracteres -- um espaco, uma barra normal, duas barras invertidas e um ponto. O to_set '----' tem apenas quatro hifens. O espaco, a barra normal e a barra invertida recebem um hifen por posicao; a segunda barra invertida e uma repeticao e por isso e ignorada (veja o aviso abaixo), e o ponto fica sem par e e removido -- ele nao vira hifen. Se voce quiser manter o ponto como hifen, de a ele um quinto hifen no to_set; os tamanhos dos conjuntos precisam refletir sua intencao com exatidao, senao os caracteres sem par do from_set sao apagados em vez de substituidos.
Gotcha: os caracteres do from_set devem ser unicos. Se um se repete, so a primeira ocorrencia conta. TRANSLATE('a', 'aa', 'xy') resulta em 'x', nao 'y': o segundo a e ignorado.
A diferenca central para o REPLACE
O REPLACE encontra e troca uma substring inteira; o TRANSLATE trabalha caractere a caractere, sem depender da ordem.
SELECT REPLACE('a.b.c', '.', '_');
SELECT TRANSLATE('a.b,c;d', '.,;', '___');
Para remover tres separadores diferentes com REPLACE, voce precisa de tres chamadas aninhadas; o TRANSLATE faz isso com um unico conjunto.
- Precisa trocar uma palavra ou um token de varios caracteres? Isso e
REPLACE.
- Precisa mapear ou apagar um conjunto de caracteres individuais? Isso e
TRANSLATE.
Notas por motor
- PostgreSQL:
TRANSLATE(text, from, to) completo; a remocao com to_set curto funciona como descrito acima no exemplo do ponto.
- Oracle: tambem existe, mas o
to_set nao pode ser string vazia (e tratado como NULL e o resultado vira NULL). Para apagar caracteres, passe um to_set nao vazio mais curto que o from_set.
- MySQL/MariaDB: nao ha funcao
TRANSLATE. Emule com REPLACE aninhados ou REGEXP_REPLACE.
- ClickHouse: oferece
translate(s, from, to) e translateUTF8 para lidar bem com caracteres multibyte.
SELECT translateUTF8(name, 'aeiou', 'AEIOU') FROM users;
A verdadeira armadilha do TRANSLATE nao e a troca em si, mas os casos limite onde os conjuntos se encontram: um from_set maior que o to_set (o excedente e apagado), uma duplicata no from_set (so a primeira ocorrencia conta) e os caracteres multibyte na variante por bytes. Antes de portar a logica de slug entre PostgreSQL, MySQL e ClickHouse, rode uma tabela pequena com NULL, string vazia e nao-ASCII: os motores concordam em dados limpos e divergem justamente nessas bordas, como o ponto no exemplo acima.
Lembre-se: na maioria dos motores o TRANSLATE opera sobre code points ou bytes, entao para nao-ASCII use a variante compativel com UTF-8 (translateUTF8 no ClickHouse) quando existir.
O
TRANSLATErecebe uma string e dois mapas de caracteres equivalentes: cada caractere do primeiro conjunto e trocado pelo da mesma posicao no segundo. E uma operacao caractere a caractere, nao de substrings, e e exatamente isso que a separa doREPLACE. Use-o quando precisar limpar ou normalizar caracteres individuais -- separadores, pontuacao, letras parecidas -- em uma unica passada, sem chamadas aninhadas nem expressoes regulares.Sintaxe basica
A assinatura e simples:
TRANSLATE(text, from_set, to_set). O caracterefrom_set[i]virato_set[i].SELECT TRANSLATE('abc', 'abc', 'xyz'); -- 'xyz' SELECT TRANSLATE('a-b-c', 'abc', 'xyz'); -- 'x-y-z'Os hifens ficam no lugar: nao estao no
from_set, entao nao sao tocados. OTRANSLATEprocessa cada caractere de forma independente e em uma unica passada.from_setsao copiados sem alteracao.aeAsao caracteres diferentes.Apagar caracteres: quando
to_sete mais curtoSe um caractere nao tem par no segundo conjunto, ele e removido. Esse e o uso mais pratico do
TRANSLATE.-- Normalize phone numbers: drop separators entirely SELECT id, TRANSLATE(name, ' .,()-+', '') AS cleaned FROM users;Aqui o
to_setesta vazio, entao cada separador listado simplesmente some. Um caso comum e tirar a formatacao de telefones ou SKUs:-- Strip spaces, dashes and parens from a stored code SELECT TRANSLATE('+1 (555) 123-45-67', ' ()-+', ''); -- '15551234567'O mesmo truque arruma os status de pedido antes de um export:
SELECT id, TRANSLATE(status, '_', ' ') AS label FROM orders;Transliteracao em uma passada
O
TRANSLATEe otimo para criar valores tipo slug ou normalizar caracteres. Mapeie cada caractere "perigoso" para um seguro em uma unica chamada:-- Map separators and odd punctuation in one shot SELECT id, TRANSLATE(LOWER(name), ' /\\.', '----') AS slug_part FROM employees;Leia esses literais ao pe da letra. O
from_sete escrito' /\\.': dentro de aspas simples o PostgreSQL le\\como dois caracteres de barra invertida, entao o conjunto tem cinco caracteres -- um espaco, uma barra normal, duas barras invertidas e um ponto. Oto_set'----'tem apenas quatro hifens. O espaco, a barra normal e a barra invertida recebem um hifen por posicao; a segunda barra invertida e uma repeticao e por isso e ignorada (veja o aviso abaixo), e o ponto fica sem par e e removido -- ele nao vira hifen. Se voce quiser manter o ponto como hifen, de a ele um quinto hifen noto_set; os tamanhos dos conjuntos precisam refletir sua intencao com exatidao, senao os caracteres sem par dofrom_setsao apagados em vez de substituidos.A diferenca central para o REPLACE
O
REPLACEencontra e troca uma substring inteira; oTRANSLATEtrabalha caractere a caractere, sem depender da ordem.-- REPLACE swaps a whole substring SELECT REPLACE('a.b.c', '.', '_'); -- 'a_b_c' -- TRANSLATE maps single chars; great for sets SELECT TRANSLATE('a.b,c;d', '.,;', '___'); -- 'a_b_c_d'Para remover tres separadores diferentes com
REPLACE, voce precisa de tres chamadas aninhadas; oTRANSLATEfaz isso com um unico conjunto.REPLACE.TRANSLATE.Notas por motor
TRANSLATE(text, from, to)completo; a remocao comto_setcurto funciona como descrito acima no exemplo do ponto.to_setnao pode ser string vazia (e tratado como NULL e o resultado vira NULL). Para apagar caracteres, passe umto_setnao vazio mais curto que ofrom_set.TRANSLATE. Emule comREPLACEaninhados ouREGEXP_REPLACE.translate(s, from, to)etranslateUTF8para lidar bem com caracteres multibyte.-- ClickHouse: byte-wise vs UTF-8 aware SELECT translateUTF8(name, 'aeiou', 'AEIOU') FROM users;A verdadeira armadilha do
TRANSLATEnao e a troca em si, mas os casos limite onde os conjuntos se encontram: umfrom_setmaior que oto_set(o excedente e apagado), uma duplicata nofrom_set(so a primeira ocorrencia conta) e os caracteres multibyte na variante por bytes. Antes de portar a logica de slug entre PostgreSQL, MySQL e ClickHouse, rode uma tabela pequena com NULL, string vazia e nao-ASCII: os motores concordam em dados limpos e divergem justamente nessas bordas, como o ponto no exemplo acima.Lembre-se: na maioria dos motores o
TRANSLATEopera sobre code points ou bytes, entao para nao-ASCII use a variante compativel com UTF-8 (translateUTF8no ClickHouse) quando existir.