sqlpostgresqlstringsmysql

SPLIT_PART en PostgreSQL: dividir una cadena y tomar el campo N

Extrae el dominio de un email, un segmento de una ruta o un codigo de un SKU con una sola llamada a SPLIT_PART, y sus equivalentes en MySQL y ClickHouse.

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

SPLIT_PART corta una cadena por un separador fijo y devuelve un solo campo segun su posicion. Es la forma mas directa de extraer el dominio de un email, un segmento de una ruta o un codigo de un SKU, sin recurrir a expresiones regulares.

Sintaxis y ejemplo basico

La firma es sencilla: SPLIT_PART(string, delimiter, n). La cadena se divide por delimiter, los campos se numeran desde 1 y la funcion devuelve el campo n-esimo como texto.

SELECT SPLIT_PART(email, '@', 2) AS domain
FROM users;

Algunos comportamientos que conviene recordar:

  • Los campos se numeran desde uno, no desde cero. SPLIT_PART('a.b.c', '.', 1) devuelve a.
  • Si el campo n no existe, obtienes una cadena vacia '', no NULL.
  • Si el separador no aparece, todo el valor se trata como el campo numero 1.
  • delimiter es un literal, no una regex; un punto significa un punto.

Casos reales

Dominios de usuarios y reparto por proveedor de correo:

SELECT
    SPLIT_PART(email, '@', 2) AS domain,
    COUNT(*)                  AS users
FROM users
GROUP BY SPLIT_PART(email, '@', 2)
ORDER BY users DESC;

La parte local (antes de @) es simplemente el campo numero 1:

SELECT id, SPLIT_PART(email, '@', 1) AS local_part
FROM users
WHERE country = 'ES';

Descomponer un estado de pedido compuesto como paid:card:eur:

SELECT
    id,
    SPLIT_PART(status, ':', 1) AS payment_state,
    SPLIT_PART(status, ':', 2) AS method,
    SPLIT_PART(status, ':', 3) AS currency
FROM orders;

El primer segmento de un codigo de departamento jerarquico como eng/backend/payments:

SELECT name, SPLIT_PART(dept, '/', 1) AS top_level_dept
FROM employees;

Indice negativo en PostgreSQL 14+

Desde PostgreSQL 14 el tercer argumento puede ser negativo y cuenta desde el final. Es una bendicion cuando el numero de segmentos varia pero quieres justo el ultimo.

-- PostgreSQL 14+: ultimo segmento de la ruta
SELECT SPLIT_PART('eng/backend/payments', '/', -1);  -- 'payments'

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

Trampa: antes de la version 14 un indice negativo lanza un error en lugar de devolver una cadena vacia. Si tu codigo corre en PostgreSQL 13 o anterior, emula el "ultimo campo" con reverse() o regexp_replace(path, '.*/', ''). Confirma siempre la version del servidor antes de depender del conteo negativo.

MySQL: SUBSTRING_INDEX

MySQL no tiene SPLIT_PART, pero ofrece SUBSTRING_INDEX(str, delim, count). La logica es distinta: un count positivo toma todo lo que hay antes del N-esimo separador por la izquierda, y uno negativo por la derecha. Para aislar un solo campo se anidan dos llamadas.

-- MySQL: dominio de un email (todo lo que sigue al primer '@')
SELECT SUBSTRING_INDEX(email, '@', -1) AS domain
FROM users;

-- MySQL: exactamente el segundo campo de 'a.b.c.d'
-- toma los dos primeros campos y luego el ultimo de ellos
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a.b.c.d', '.', 2), '.', -1);  -- 'b'

Para cadenas de dos campos (como local@domain) basta una sola llamada SUBSTRING_INDEX(..., -1). Para un N arbitrario necesitas el sandwich de dos llamadas.

ClickHouse: splitByChar y arrays

ClickHouse piensa en arrays: splitByChar(delim, str) devuelve un array de campos del que indexas el elemento que quieres (numerado desde 1). Para un separador de varios caracteres existe splitByString.

-- ClickHouse: dominio de un email
SELECT splitByChar('@', email)[2] AS domain
FROM users;

-- ClickHouse: ultimo segmento con arrayElement e indice negativo
SELECT arrayElement(splitByChar('/', 'eng/backend/payments'), -1);  -- 'payments'

Resumen rapido por dialecto:

  • PostgreSQL: SPLIT_PART(s, d, n), campos desde 1, n negativo desde PG14.
  • MySQL: SUBSTRING_INDEX, doble llamada para aislar un campo.
  • ClickHouse: splitByChar/splitByString mas indexacion de array.

Cuando una cadena tiene muchos separadores y la logica supera el simple "campo N-esimo", en PostgreSQL encajan mejor regexp_split_to_array o regexp_match. Pero para un parseo limpio y predecible, SPLIT_PART sigue siendo la herramienta mas corta y legible que tienes.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador