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.
SELECT SPLIT_PART('eng/backend/payments', '/', -1);
SELECT SPLIT_PART('eng/backend/payments', '/', -2);
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.
SELECT SUBSTRING_INDEX(email, '@', -1) AS domain
FROM users;
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a.b.c.d', '.', 2), '.', -1);
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.
SELECT splitByChar('@', email)[2] AS domain
FROM users;
SELECT arrayElement(splitByChar('/', 'eng/backend/payments'), -1);
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.
SPLIT_PARTcorta 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 pordelimiter, los campos se numeran desde1y la funcion devuelve el campon-esimo como texto.SELECT SPLIT_PART(email, '@', 2) AS domain FROM users;Algunos comportamientos que conviene recordar:
SPLIT_PART('a.b.c', '.', 1)devuelvea.nno existe, obtienes una cadena vacia'', noNULL.1.delimiteres 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 numero1: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'MySQL: SUBSTRING_INDEX
MySQL no tiene
SPLIT_PART, pero ofreceSUBSTRING_INDEX(str, delim, count). La logica es distinta: uncountpositivo 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 llamadaSUBSTRING_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 desde1). Para un separador de varios caracteres existesplitByString.-- 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:
SPLIT_PART(s, d, n), campos desde1,nnegativo desde PG14.SUBSTRING_INDEX, doble llamada para aislar un campo.splitByChar/splitByStringmas 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_arrayoregexp_match. Pero para un parseo limpio y predecible,SPLIT_PARTsigue siendo la herramienta mas corta y legible que tienes.