sqlpostgresqlregexarrays

REGEXP_SPLIT_TO_ARRAY: dividir strings por um delimitador regex

Como dividir strings por regex em array ou linhas e por que isso supera SPLIT_PART em dados baguncados.

2 min de leituraReferênciasql · postgresql · regex · arrays · string-functions

Quando os dados chegam espremidos em uma unica coluna de texto — tags separadas por virgula, uma lista de emails com espacos soltos, um caminho de gerentes — um delimitador fixo deixa de bastar. REGEXP_SPLIT_TO_ARRAY e REGEXP_SPLIT_TO_TABLE cortam a string por uma expressao regular, engolindo espacos irregulares e separadores repetidos em uma unica passada.

Divisao basica por regex

Ambas as funcoes recebem uma string e um delimitador regex. A primeira retorna um array text[]; a segunda, um conjunto de linhas.

-- Tolerate any whitespace around commas
SELECT regexp_split_to_array('a, b,c ,  d', '\s*,\s*');
-- {a,b,c,d}

-- Same delimiter, one row per element
SELECT regexp_split_to_table('a, b,c ,  d', '\s*,\s*') AS tag;

O delimitador \s*,\s* significa "uma virgula cercada por qualquer quantidade de espacos". Por isso b,c e , d saem igualmente limpos, sem um TRIM por elemento para vigiar.

Entrada tipo CSV e UNNEST

Digamos que users.name guarda temporariamente varios nomes separados por virgula, ou voce recebeu uma lista de paises em uma unica string. Divida em um array e depois expanda com UNNEST.

WITH raw(id, countries) AS (
  VALUES (1, 'US,  CA ,MX'),
         (2, 'BR , AR')
)
SELECT r.id, c.country
FROM raw r
CROSS JOIN LATERAL unnest(
  regexp_split_to_array(r.countries, '\s*,\s*')
) AS c(country);

REGEXP_SPLIT_TO_TABLE entrega o mesmo formato sem o array intermediario:

SELECT u.id,
       regexp_split_to_table(u.email, '[;,]\s*') AS one_email
FROM users u
WHERE u.email LIKE '%,%' OR u.email LIKE '%;%';

A classe [;,] divide por virgula ou por ponto e virgula — a realidade comum quando os formatos de exportacao estao misturados.

Quando SPLIT_PART basta

Se o delimitador for exatamente um caractere e voce quiser um segmento especifico por indice, SPLIT_PART e mais simples e rapido: ele nunca liga o motor de regex.

-- Domain part of a clean email
SELECT id, split_part(email, '@', 2) AS domain
FROM users;

-- Top-level dept from a path like 'eng/backend/payments'
SELECT id, split_part(dept, '/', 1) AS top_dept
FROM employees;

Regra pratica para escolher:

  • Delimitador unico fixo + voce quer o N-esimo pedaco → SPLIT_PART.
  • Espacos variaveis, varias variantes de delimitador, voce quer todas as partes → REGEXP_SPLIT_TO_ARRAY / _TABLE.

Pegadinha: elementos vazios e ancoras

SPLIT_PART comeca no indice 1 e retorna uma string vazia (nao NULL) quando erra. A divisao por regex tem sua propria armadilha: se o delimitador casar no inicio ou no fim da string, voce recebe elementos vazios.

-- Leading/trailing comma produces empty slots
SELECT regexp_split_to_array(',a,b,', ',');
-- {"",a,b,""}

Limpe a entrada antes, ou filtre depois do UNNEST:

SELECT id, amount
FROM orders, LATERAL unnest(
  regexp_split_to_array(status, '\s*,\s*')
) AS s(item)
WHERE s.item <> '';

Diferencas em outros bancos

  • MySQL nao tem equivalente direto: antes do 8.0 voce expande uma string com um CTE recursivo sobre SUBSTRING_INDEX; a partir do 8.0.4 ha REGEXP_SUBSTR/REGEXP_REPLACE, mas nao ha split-para-tabela — JSON_TABLE costuma ser mais facil.
  • ClickHouse usa splitByRegexp(pattern, s) (e splitByChar para um caractere fixo), retornando Array(String), que voce expande com arrayJoin.
  • No PostgreSQL, as flags vao em um terceiro argumento: regexp_split_to_array(s, 'x', 'i') para correspondencia sem diferenciar maiusculas.

Guarde SPLIT_PART para casos limpos de um unico caractere, e use REGEXP_SPLIT_TO_ARRAY para qualquer coisa minimamente baguncada.

Pratique com exercícios reais

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

Abrir o treinador