sqlpostgresqlstring-functionstrim

BTRIM, LTRIM e RTRIM no SQL: removendo espacos e qualquer caractere

Como remover espacos e caracteres arbitrarios das bordas de uma string com BTRIM, LTRIM e RTRIM e a relacao com o TRIM padrao.

3 min de leituraReferênciasql · postgresql · string-functions · trim · data-cleaning

Strings sujas sao o normal: espacos extras vindos de formularios, zeros a esquerda em codigos, barras no fim de URLs. BTRIM, LTRIM e RTRIM removem caracteres das bordas de uma string e resolvem a maioria desses casos com uma unica funcao.

As tres compartilham uma propriedade essencial: cortam apenas nas bordas e nunca tocam o miolo. BTRIM('a b', ' ') devolve 'a b' sem alteracao — os espacos entre as palavras permanecem, somente os iniciais e finais saem. Isso as distingue de REPLACE, que apagaria os espacos da string inteira. Por padrao as tres removem espacos, mas um segundo argumento permite indicar qualquer conjunto de caracteres — zeros, barras, hifens, simbolos de moeda — e essa flexibilidade e a maior vantagem sobre o TRIM padrao puro.

Tres funcoes e o que cada uma corta

No PostgreSQL a familia e simetrica:

  • LTRIM(s) — remove caracteres a esquerda (no inicio);
  • RTRIM(s) — remove caracteres a direita (no fim);
  • BTRIM(s) — remove das duas pontas.

Por padrao removem espacos. Mas cada funcao aceita um segundo argumento: o conjunto de caracteres a remover.

SELECT
  LTRIM('   hello   ')        AS left_only,    -- 'hello   '
  RTRIM('   hello   ')        AS right_only,   -- '   hello'
  BTRIM('   hello   ')        AS both_sides;   -- 'hello'

Um ponto importante: o segundo argumento nao e uma substring, e um conjunto de caracteres. BTRIM('xxyhelloyxx', 'xy') remove qualquer caractere inicial e final que pertenca a {'x','y'}, em qualquer ordem, ate encontrar algo diferente.

Normalizando dados de usuario

O caso mais comum e limpar email e name antes de inserir ou comparar. Espacos nas bordas quebram a unicidade e os joins.

-- Normalize on read
SELECT id, BTRIM(LOWER(email)) AS email_clean
FROM users
WHERE BTRIM(email) <> '';

-- Fix existing rows in place
UPDATE users
SET name = BTRIM(name)
WHERE name <> BTRIM(name);

O predicado name <> BTRIM(name) atualiza apenas as linhas realmente sujas: e mais barato e evita encher o log com atualizacoes sem efeito.

Removendo caracteres arbitrarios: zeros e barras

Aqui o conjunto de caracteres mostra todo o seu valor. Vamos tirar zeros a esquerda de um codigo e a barra final de um caminho.

SELECT
  LTRIM('00042', '0')                 AS code,    -- '42'
  RTRIM('https://shop.dev/api/', '/') AS endpoint,-- 'https://shop.dev/api'
  BTRIM('--draft--', '-')             AS status;  -- 'draft'

Um exemplo pratico sobre orders: os status as vezes chegam com marcadores de envolucro, e os valores vem como texto com simbolo de moeda.

SELECT
  id,
  BTRIM(status, '*')                     AS status,
  LTRIM(CAST(amount AS text), '$') AS amount_text
FROM orders
WHERE status LIKE '%*%';

Relacao com o TRIM padrao

BTRIM/LTRIM/RTRIM sao nomes do dialeto do PostgreSQL. O padrao SQL define um unico operador TRIM com palavras-chave de direcao:

SELECT
  TRIM(LEADING  '0' FROM '00042')  AS a,   -- same as LTRIM('00042','0')
  TRIM(TRAILING '/' FROM 'path/')  AS b,   -- same as RTRIM('path/','/')
  TRIM(BOTH     ' ' FROM '  x  ')  AS c;   -- same as BTRIM('  x  ')

A correspondencia e exata:

  • TRIM(LEADING c FROM s) = LTRIM(s, c);
  • TRIM(TRAILING c FROM s) = RTRIM(s, c);
  • TRIM(BOTH c FROM s) = BTRIM(s, c).

Uma sutileza: no padrao SQL o caractere de corte e um unico caractere, enquanto em BTRIM/LTRIM o segundo argumento e um conjunto de caracteres. O PostgreSQL estende o TRIM para aceitar esse mesmo conjunto, entao TRIM(BOTH 'xy' FROM s) remove qualquer x ou y das bordas, igual a BTRIM(s, 'xy'). Para "remover qualquer um destes caracteres" a forma *TRIM (ou o TRIM do PostgreSQL) se encaixa melhor, mas nao suponha que todo motor le esse argumento da mesma maneira.

Diferencas no MySQL e no ClickHouse

  • MySQL: existem TRIM, LTRIM, RTRIM, mas LTRIM/RTRIM nao aceitam segundo argumento: removem apenas espacos. Nao ha BTRIM; use TRIM(BOTH 'x' FROM s), mas lembre que aqui o argumento e uma substring (remstr), nao um conjunto de caracteres.
  • ClickHouse: tem trimLeft, trimRight, trimBoth, mas eles tambem removem apenas espacos. Para caracteres arbitrarios use trim(LEADING 'x' FROM s) ou uma expressao regular como replaceRegexpOne.

A maior armadilha e confundir "conjunto de caracteres" com "substring". RTRIM('abcxyz', 'zyx') no PostgreSQL retorna 'abc' porque corta do fim cada caractere do conjunto {z,y,x}, um a um, sem importar a ordem. TRIM(TRAILING 'zyx' FROM 'abcxyz') no MySQL retorna a string intacta, porque a substring literal 'zyx' nao casa no fim; apenas 'xyz' casaria como substring inteira. Troque a ordem das letras e o resultado do MySQL muda, enquanto o do PostgreSQL nao. Confirme sempre se o seu motor trata o argumento como um conjunto de caracteres ou como uma substring.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador