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.
SELECT regexp_split_to_array('a, b,c , d', '\s*,\s*');
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.
SELECT id, split_part(email, '@', 2) AS domain
FROM users;
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.
SELECT regexp_split_to_array(',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.
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_ARRAYeREGEXP_SPLIT_TO_TABLEcortam 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 issob,ce, dsaem igualmente limpos, sem umTRIMpor elemento para vigiar.Entrada tipo CSV e UNNEST
Digamos que
users.nameguarda temporariamente varios nomes separados por virgula, ou voce recebeu uma lista de paises em uma unica string. Divida em um array e depois expanda comUNNEST.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_TABLEentrega 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_PARTe 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:
SPLIT_PART.REGEXP_SPLIT_TO_ARRAY/_TABLE.Pegadinha: elementos vazios e ancoras
SPLIT_PARTcomeca 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
SUBSTRING_INDEX; a partir do 8.0.4 haREGEXP_SUBSTR/REGEXP_REPLACE, mas nao ha split-para-tabela —JSON_TABLEcostuma ser mais facil.splitByRegexp(pattern, s)(esplitByCharpara um caractere fixo), retornandoArray(String), que voce expande comarrayJoin.regexp_split_to_array(s, 'x', 'i')para correspondencia sem diferenciar maiusculas.Guarde
SPLIT_PARTpara casos limpos de um unico caractere, e useREGEXP_SPLIT_TO_ARRAYpara qualquer coisa minimamente baguncada.