sqlpostgresqlstringsmysql

SPLIT_PART no PostgreSQL: dividir uma string e pegar o N-esimo campo

Extraia o dominio de um email, um segmento de um caminho ou um codigo de um SKU com uma chamada a SPLIT_PART, alem dos equivalentes em MySQL e ClickHouse.

2 min de leituraReferencesql · postgresql · strings · mysql · clickhouse

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.

-- PostgreSQL 14+: ultimo segmento da rota
SELECT SPLIT_PART('eng/backend/payments', '/', -1);  -- 'payments'

-- penultimo
SELECT SPLIT_PART('eng/backend/payments', '/', -2);  -- 'backend'

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.

-- 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 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.

-- 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:

  • 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.

Pratique com exercícios reais

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

Abrir o treinador