REVERSE e uma funcao escalar de string que retorna um texto lido de tras para frente. Parece um brinquedo, mas e justamente o que transforma uma busca "termina com" em algo indexavel, verifica palindromos em uma unica expressao e inverte listas com elegancia.
Sintaxe e exemplo basico
A assinatura e simples ao maximo: REVERSE(string). Ela trabalha caractere a caractere e retorna texto do mesmo tipo.
SELECT REVERSE('postgres') AS flipped;
SELECT id, name, REVERSE(name) AS name_rev
FROM users;
Alguns comportamentos que vale guardar:
REVERSE opera sobre caracteres, nao sobre bytes, e inverte corretamente os caracteres multibyte UTF-8.
NULL na entrada produz NULL na saida, entao nenhum tratamento especial e necessario.
- O resultado e deterministico e independente da collation: o que e reordenado sao os caracteres.
Um indice por sufixo para buscas "termina com"
Uma dor classica: WHERE email LIKE '%@gmail.com' nao consegue usar um indice B-tree comum, porque o padrao comeca com %. O truque e inverter a string para que o "sufixo" vire "prefixo", e a busca por prefixo e indexavel.
CREATE INDEX idx_users_email_rev
ON users (REVERSE(email) text_pattern_ops);
SELECT id, email
FROM users
WHERE REVERSE(email) LIKE REVERSE('%@gmail.com');
Apos o REVERSE, o padrao '%@gmail.com' vira 'moc.liamg@%', um prefixo ancorado moc.liamg@, de modo que o planejador pode percorrer o indice de expressao.
- A classe de operadores
text_pattern_ops e obrigatoria para prefixos LIKE fora da locale C.
- A expressao do
WHERE precisa coincidir literalmente com a do indice, ou o indice nao sera usado.
- Uma alternativa sem
REVERSE e email LIKE '%@gmail.com' mais a extensao pg_trgm com um indice GIN, mas para um "termina com" estrito o prefixo invertido e mais preciso e leve.
Pegadinha: um indice sobre REVERSE(email) so acelera buscas por final. Ele nao cobre uma consulta comum email LIKE 'john%' (comeca com), que precisa do proprio indice sobre a coluna original.
Verificacao de palindromos
Um palindromo e uma string igual ao seu reflexo. Com REVERSE isso e uma unica expressao, sem procedimentos nem lacos.
SELECT name
FROM users
WHERE LOWER(name) = REVERSE(LOWER(name));
LOWER aqui remove a distincao de maiusculas, entao Anna conta como palindromo. Para ignorar espacos e pontuacao, normalize a string primeiro:
SELECT name,
regexp_replace(LOWER(name), '[^a-z0-9]', '', 'g') AS norm
FROM users
WHERE regexp_replace(LOWER(name), '[^a-z0-9]', '', 'g')
= REVERSE(regexp_replace(LOWER(name), '[^a-z0-9]', '', 'g'));
REVERSE inverte caracteres, nao elementos. Para transformar a lista 'a,b,c' em 'c,b,a', divida, inverta a ordem e junte de volta. No PostgreSQL o caminho legivel e string_to_array mais unnest ordenado de forma decrescente e depois string_agg.
SELECT string_agg(part, ',') AS reversed_list
FROM (
SELECT part, ord
FROM unnest(string_to_array('mon,tue,wed', ',')) WITH ORDINALITY AS t(part, ord)
ORDER BY ord DESC
) s;
Quando voce so precisa de um elemento a partir do final, como o dominio de topo de a.b.com, combine REVERSE com SPLIT_PART:
SELECT REVERSE(SPLIT_PART(REVERSE('mail.corp.example.com'), '.', 1)) AS tld;
Aqui invertemos a string, pegamos o primeiro segmento (o ultimo no original) e o invertemos de volta. E o movimento canonico de "indexar a partir do final".
Multibyte e diferencas entre motores
REVERSE no PostgreSQL e seguro com Unicode: opera sobre pontos de codigo, nao sobre bytes. Mas ha nuances comuns a todos os motores:
- Grafemas compostos (uma letra mais um acento combinante, ou um emoji com modificadores) podem quebrar ao serem invertidos, porque pontos de codigo sao reordenados, nao grafemas. Para texto com diacriticos essa e uma armadilha rara, mas real.
- No MySQL a funcao tambem e
REVERSE e e segura com multibyte sob um charset UTF-8; garanta que a coluna seja utf8mb4, ou os emojis sao corrompidos antes mesmo da inversao.
- No ClickHouse existem um
reverse em nivel de byte e um reverseUTF8 - para strings nao ASCII use reverseUTF8, ou voce obtem uma sequencia de bytes quebrada.
Quando voce precisa de um "termina com" indexavel, uma verificacao de palindromo previsivel ou acesso a um elemento a partir do final, REVERSE continua sendo a ferramenta mais direta - apenas lembre que ela reordena caracteres, nao grafemas nem elementos de lista.
REVERSEe uma funcao escalar de string que retorna um texto lido de tras para frente. Parece um brinquedo, mas e justamente o que transforma uma busca "termina com" em algo indexavel, verifica palindromos em uma unica expressao e inverte listas com elegancia.Sintaxe e exemplo basico
A assinatura e simples ao maximo:
REVERSE(string). Ela trabalha caractere a caractere e retorna texto do mesmo tipo.SELECT REVERSE('postgres') AS flipped; -- 'sergtsop' SELECT id, name, REVERSE(name) AS name_rev FROM users;Alguns comportamentos que vale guardar:
REVERSEopera sobre caracteres, nao sobre bytes, e inverte corretamente os caracteres multibyte UTF-8.NULLna entrada produzNULLna saida, entao nenhum tratamento especial e necessario.Um indice por sufixo para buscas "termina com"
Uma dor classica:
WHERE email LIKE '%@gmail.com'nao consegue usar um indice B-tree comum, porque o padrao comeca com%. O truque e inverter a string para que o "sufixo" vire "prefixo", e a busca por prefixo e indexavel.CREATE INDEX idx_users_email_rev ON users (REVERSE(email) text_pattern_ops); -- ends-with becomes a prefix scan on the reversed value SELECT id, email FROM users WHERE REVERSE(email) LIKE REVERSE('%@gmail.com');Apos o
REVERSE, o padrao'%@gmail.com'vira'moc.liamg@%', um prefixo ancoradomoc.liamg@, de modo que o planejador pode percorrer o indice de expressao.text_pattern_opse obrigatoria para prefixosLIKEfora da localeC.WHEREprecisa coincidir literalmente com a do indice, ou o indice nao sera usado.REVERSEeemail LIKE '%@gmail.com'mais a extensaopg_trgmcom um indice GIN, mas para um "termina com" estrito o prefixo invertido e mais preciso e leve.Verificacao de palindromos
Um palindromo e uma string igual ao seu reflexo. Com
REVERSEisso e uma unica expressao, sem procedimentos nem lacos.SELECT name FROM users WHERE LOWER(name) = REVERSE(LOWER(name));LOWERaqui remove a distincao de maiusculas, entaoAnnaconta como palindromo. Para ignorar espacos e pontuacao, normalize a string primeiro:SELECT name, regexp_replace(LOWER(name), '[^a-z0-9]', '', 'g') AS norm FROM users WHERE regexp_replace(LOWER(name), '[^a-z0-9]', '', 'g') = REVERSE(regexp_replace(LOWER(name), '[^a-z0-9]', '', 'g'));Inverter uma lista com delimitador
REVERSEinverte caracteres, nao elementos. Para transformar a lista'a,b,c'em'c,b,a', divida, inverta a ordem e junte de volta. No PostgreSQL o caminho legivel estring_to_arraymaisunnestordenado de forma decrescente e depoisstring_agg.-- reverse the ELEMENTS of a delimited list, not the characters SELECT string_agg(part, ',') AS reversed_list FROM ( SELECT part, ord FROM unnest(string_to_array('mon,tue,wed', ',')) WITH ORDINALITY AS t(part, ord) ORDER BY ord DESC ) s; -- 'wed,tue,mon'Quando voce so precisa de um elemento a partir do final, como o dominio de topo de
a.b.com, combineREVERSEcomSPLIT_PART:-- last segment of a dotted host, taken as the first segment after REVERSE SELECT REVERSE(SPLIT_PART(REVERSE('mail.corp.example.com'), '.', 1)) AS tld; -- 'com'Aqui invertemos a string, pegamos o primeiro segmento (o ultimo no original) e o invertemos de volta. E o movimento canonico de "indexar a partir do final".
Multibyte e diferencas entre motores
REVERSEno PostgreSQL e seguro com Unicode: opera sobre pontos de codigo, nao sobre bytes. Mas ha nuances comuns a todos os motores:REVERSEe e segura com multibyte sob um charset UTF-8; garanta que a coluna sejautf8mb4, ou os emojis sao corrompidos antes mesmo da inversao.reverseem nivel de byte e umreverseUTF8- para strings nao ASCII usereverseUTF8, ou voce obtem uma sequencia de bytes quebrada.Quando voce precisa de um "termina com" indexavel, uma verificacao de palindromo previsivel ou acesso a um elemento a partir do final,
REVERSEcontinua sendo a ferramenta mais direta - apenas lembre que ela reordena caracteres, nao grafemas nem elementos de lista.