SPLIT_PART corta uma string por um separador fixo e devolve um unico campo pela sua posicao. E a forma mais direta de extrair o dominio de um email, um segmento de uma rota ou um codigo de um SKU, sem recorrer a expressoes regulares.
Sintaxe e exemplo basico
A assinatura e simples: SPLIT_PART(string, delimiter, n). A string e dividida por delimiter, os campos sao numerados a partir de 1 e a funcao retorna o n-esimo campo como texto.
SELECT SPLIT_PART(email, '@', 2) AS domain
FROM users;
Alguns comportamentos que vale a pena lembrar:
- Os campos sao numerados a partir de um, nao de zero.
SPLIT_PART('a.b.c', '.', 1) retorna a.
- Se o campo
n nao existe, voce recebe uma string vazia '', nao NULL.
- Se o separador nao aparece, o valor inteiro e tratado como o campo numero
1.
delimiter e um literal, nao uma regex; um ponto significa um ponto.
Cenarios reais
Dominios de usuarios e a distribuicao por provedor de email:
SELECT
SPLIT_PART(email, '@', 2) AS domain,
COUNT(*) AS users
FROM users
GROUP BY SPLIT_PART(email, '@', 2)
ORDER BY users DESC;
A parte local (antes do @) e simplesmente o campo numero 1:
SELECT id, SPLIT_PART(email, '@', 1) AS local_part
FROM users
WHERE country = 'BR';
Decompor um status de pedido composto como paid:card:brl:
SELECT
id,
SPLIT_PART(status, ':', 1) AS payment_state,
SPLIT_PART(status, ':', 2) AS method,
SPLIT_PART(status, ':', 3) AS currency
FROM orders;
O primeiro segmento de um codigo de departamento hierarquico como eng/backend/payments:
SELECT name, SPLIT_PART(dept, '/', 1) AS top_level_dept
FROM employees;
Indice negativo no PostgreSQL 14+
A partir do PostgreSQL 14 o terceiro argumento pode ser negativo e conta a partir do fim. Isso salva a vida quando o numero de segmentos varia mas voce quer justamente o ultimo.
SELECT SPLIT_PART('eng/backend/payments', '/', -1);
SELECT SPLIT_PART('eng/backend/payments', '/', -2);
Pegadinha: antes da versao 14 um indice negativo gera um erro em vez de retornar uma string vazia. Se o seu codigo roda no PostgreSQL 13 ou anterior, emule o "ultimo campo" com reverse() ou regexp_replace(path, '.*/', ''). Sempre confirme a versao do servidor antes de depender da contagem negativa.
MySQL: SUBSTRING_INDEX
O MySQL nao tem SPLIT_PART, mas oferece SUBSTRING_INDEX(str, delim, count). A logica e diferente: um count positivo pega tudo que vem antes do N-esimo separador pela esquerda, e um negativo pela direita. Para isolar um unico campo voce aninha duas chamadas.
SELECT SUBSTRING_INDEX(email, '@', -1) AS domain
FROM users;
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a.b.c.d', '.', 2), '.', -1);
Para strings de dois campos (como local@domain) uma unica chamada SUBSTRING_INDEX(..., -1) basta. Para um N arbitrario voce precisa do sanduiche de duas chamadas.
ClickHouse: splitByChar e arrays
O ClickHouse pensa em arrays: splitByChar(delim, str) retorna um array de campos do qual voce indexa o elemento desejado (numerado a partir de 1). Para um separador de varios caracteres existe splitByString.
SELECT splitByChar('@', email)[2] AS domain
FROM users;
SELECT arrayElement(splitByChar('/', 'eng/backend/payments'), -1);
Resumo rapido por dialeto:
- PostgreSQL:
SPLIT_PART(s, d, n), campos a partir de 1, n negativo desde o PG14.
- MySQL:
SUBSTRING_INDEX, chamada dupla para isolar um campo.
- ClickHouse:
splitByChar/splitByString mais indexacao de array.
Quando uma string tem muitos separadores e a logica vai alem do simples "campo N-esimo", no PostgreSQL encaixam melhor regexp_split_to_array ou regexp_match. Mas para um parsing limpo e previsivel, SPLIT_PART continua sendo a ferramenta mais curta e legivel que voce tem.
SPLIT_PARTcorta uma string por um separador fixo e devolve um unico campo pela sua posicao. E a forma mais direta de extrair o dominio de um email, um segmento de uma rota ou um codigo de um SKU, sem recorrer a expressoes regulares.Sintaxe e exemplo basico
A assinatura e simples:
SPLIT_PART(string, delimiter, n). A string e dividida pordelimiter, os campos sao numerados a partir de1e a funcao retorna on-esimo campo como texto.SELECT SPLIT_PART(email, '@', 2) AS domain FROM users;Alguns comportamentos que vale a pena lembrar:
SPLIT_PART('a.b.c', '.', 1)retornaa.nnao existe, voce recebe uma string vazia'', naoNULL.1.delimitere um literal, nao uma regex; um ponto significa um ponto.Cenarios reais
Dominios de usuarios e a distribuicao por provedor de email:
SELECT SPLIT_PART(email, '@', 2) AS domain, COUNT(*) AS users FROM users GROUP BY SPLIT_PART(email, '@', 2) ORDER BY users DESC;A parte local (antes do
@) e simplesmente o campo numero1:SELECT id, SPLIT_PART(email, '@', 1) AS local_part FROM users WHERE country = 'BR';Decompor um status de pedido composto como
paid:card:brl:SELECT id, SPLIT_PART(status, ':', 1) AS payment_state, SPLIT_PART(status, ':', 2) AS method, SPLIT_PART(status, ':', 3) AS currency FROM orders;O primeiro segmento de um codigo de departamento hierarquico como
eng/backend/payments:SELECT name, SPLIT_PART(dept, '/', 1) AS top_level_dept FROM employees;Indice negativo no PostgreSQL 14+
A partir do PostgreSQL 14 o terceiro argumento pode ser negativo e conta a partir do fim. Isso salva a vida quando o numero de segmentos varia mas voce quer justamente o ultimo.
-- PostgreSQL 14+: ultimo segmento da rota SELECT SPLIT_PART('eng/backend/payments', '/', -1); -- 'payments' -- penultimo SELECT SPLIT_PART('eng/backend/payments', '/', -2); -- 'backend'MySQL: SUBSTRING_INDEX
O MySQL nao tem
SPLIT_PART, mas ofereceSUBSTRING_INDEX(str, delim, count). A logica e diferente: umcountpositivo pega tudo que vem antes do N-esimo separador pela esquerda, e um negativo pela direita. Para isolar um unico campo voce aninha duas chamadas.-- MySQL: dominio de um email (tudo apos o primeiro '@') SELECT SUBSTRING_INDEX(email, '@', -1) AS domain FROM users; -- MySQL: exatamente o segundo campo de 'a.b.c.d' -- pega os dois primeiros campos e depois o ultimo deles SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a.b.c.d', '.', 2), '.', -1); -- 'b'Para strings de dois campos (como
local@domain) uma unica chamadaSUBSTRING_INDEX(..., -1)basta. Para um N arbitrario voce precisa do sanduiche de duas chamadas.ClickHouse: splitByChar e arrays
O ClickHouse pensa em arrays:
splitByChar(delim, str)retorna um array de campos do qual voce indexa o elemento desejado (numerado a partir de1). Para um separador de varios caracteres existesplitByString.-- ClickHouse: dominio de um email SELECT splitByChar('@', email)[2] AS domain FROM users; -- ClickHouse: ultimo segmento com arrayElement e indice negativo SELECT arrayElement(splitByChar('/', 'eng/backend/payments'), -1); -- 'payments'Resumo rapido por dialeto:
SPLIT_PART(s, d, n), campos a partir de1,nnegativo desde o PG14.SUBSTRING_INDEX, chamada dupla para isolar um campo.splitByChar/splitByStringmais indexacao de array.Quando uma string tem muitos separadores e a logica vai alem do simples "campo N-esimo", no PostgreSQL encaixam melhor
regexp_split_to_arrayouregexp_match. Mas para um parsing limpo e previsivel,SPLIT_PARTcontinua sendo a ferramenta mais curta e legivel que voce tem.