SUBSTRING_INDEX
La función SUBSTRING_INDEX extrae una porción de una cadena tomando como referencia las apariciones de un delimitador. En lugar de trabajar con posiciones numéricas como SUBSTRING, razona en términos de "todo lo que hay antes del segundo punto" o "lo que queda después de la última barra", lo que la hace ideal para dividir textos estructurados.
Es la herramienta perfecta para separar emails por la arroba, dominios por los puntos, nombres y apellidos por el espacio, o campos de una línea CSV por la coma. Su gran ventaja sobre la combinación de SUBSTRING con INSTR es que no necesitas calcular posiciones a mano ni preocuparte de sumar o restar uno: indicas el delimitador y cuántas apariciones quieres, y la función hace el resto. En este artículo veremos cómo funciona el conteo positivo y negativo, cómo anidar la función para extraer elementos intermedios y su comportamiento cuando el delimitador no existe.
Sintaxis
SUBSTRING_INDEX recibe la cadena, el delimitador y un número que indica cuántas apariciones del delimitador considerar y en qué dirección.
SUBSTRING_INDEX(cadena, delimitador, conteo)El signo del conteo determina desde qué lado se cuenta y qué parte se devuelve:
conteopositivo: devuelve todo lo que hay antes de la enésima aparición del delimitador, contando desde el principioconteonegativo: devuelve todo lo que hay después de la enésima aparición, contando desde el final
Ejemplo básico
Veámoslo con una dirección web separada por puntos. Con conteo 1, obtenemos todo lo anterior al primer punto:
SELECT SUBSTRING_INDEX('www.mysql.com', '.', 1) AS resultado;| resultado |
|---|
| www |
Con conteo 2, la función incluye hasta antes del segundo punto, es decir, los dos primeros segmentos:
SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2) AS resultado;| resultado |
|---|
| www.mysql |
El conteo negativo cambia la perspectiva al final de la cadena. Con -1 obtenemos lo que sigue al último delimitador, perfecto para quedarse con la extensión o el último segmento:
-- Conteo negativo: desde el final
SELECT SUBSTRING_INDEX('www.mysql.com', '.', -1) AS resultado;| resultado |
|---|
| com |
Y con -2, los dos últimos segmentos:
SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2) AS resultado;| resultado |
|---|
| mysql.com |
Separar usuario y dominio de un email
La combinación de conteo positivo y negativo permite partir un email en sus dos mitades de forma muy limpia, sin localizar la arroba manualmente:
SELECT
email,
SUBSTRING_INDEX(email, '@', -1) AS dominio,
SUBSTRING_INDEX(email, '@', 1) AS usuario
FROM clientes
LIMIT 5;| dominio | usuario | |
|---|---|---|
| maria.garcia@email.com | email.com | maria.garcia |
| carlos.rodriguez@email.com | email.com | carlos.rodriguez |
| laura.lopez@email.com | email.com | laura.lopez |
| pedro.fernandez@email.com | email.com | pedro.fernandez |
| ana.martinez@email.com | email.com | ana.martinez |
Comparado con tener que combinar SUBSTRING e INSTR y ajustar posiciones, este enfoque es mucho más directo cuando el delimitador es conocido.
Separar primer y segundo apellido
La misma técnica sirve para dividir un campo de apellidos por el espacio, obteniendo el primero con conteo positivo y el último con conteo negativo:
SELECT
nombre,
apellidos,
SUBSTRING_INDEX(apellidos, ' ', 1) AS primer_apellido,
SUBSTRING_INDEX(apellidos, ' ', -1) AS segundo_apellido
FROM clientes
LIMIT 5;| nombre | apellidos | primer_apellido | segundo_apellido |
|---|---|---|---|
| María | García López | García | López |
| Carlos | Rodríguez Martín | Rodríguez | Martín |
| Laura | López Sánchez | López | Sánchez |
| Pedro | Fernández Castro | Fernández | Castro |
| Ana | Martínez Ruiz | Martínez | Ruiz |
Extraer un campo intermedio anidando la función
Para obtener un elemento que no es ni el primero ni el último, se anida SUBSTRING_INDEX: primero se toman los segmentos hasta el que interesa con conteo positivo, y luego se extrae el último de esos con conteo negativo. Así se puede parsear una línea CSV campo a campo:
SELECT
SUBSTRING_INDEX('iPhone,1299.99,50', ',', 1) AS nombre,
SUBSTRING_INDEX(SUBSTRING_INDEX('iPhone,1299.99,50', ',', 2), ',', -1) AS precio,
SUBSTRING_INDEX('iPhone,1299.99,50', ',', -1) AS stock;| nombre | precio | stock |
|---|---|---|
| iPhone | 1299.99 | 50 |
Esta técnica del anidamiento es el patrón estándar para extraer el campo número N de una cadena delimitada, aunque para muchos campos se vuelve poco legible y conviene valorar otras estrategias.
Extraer la primera palabra
Tomar la primera palabra de un texto es tan sencillo como dividir por el espacio con conteo 1, algo útil para agrupar productos por su marca con GROUP BY:
SELECT
nombre,
SUBSTRING_INDEX(nombre, ' ', 1) AS marca
FROM productos
LIMIT 5;| nombre | marca |
|---|---|
| iPhone 15 Pro | iPhone |
| MacBook Air M2 | MacBook |
| AirPods Pro | AirPods |
| iPad Air | iPad |
| Apple Watch Series 9 | Apple |
Cuando el delimitador no existe
Conviene saber qué ocurre si el delimitador no aparece en la cadena. En ese caso, SUBSTRING_INDEX no falla ni devuelve NULL: devuelve la cadena completa, sea cual sea el conteo:
SELECT SUBSTRING_INDEX('sin-punto', '.', 1) AS resultado;| resultado |
|---|
| sin-punto |
Este comportamiento es cómodo, porque significa que extraer "la primera palabra" de un texto sin espacios devuelve el texto entero, sin necesidad de casos especiales.
Errores comunes
El malentendido más frecuente es esperar poder extraer un campo intermedio con una sola llamada. Para el segundo, tercero o enésimo elemento (que no sea el último) hay que anidar dos SUBSTRING_INDEX, y olvidarlo lleva a obtener varios campos juntos en lugar de uno solo.
Otro punto a recordar es que el delimitador se compara como texto literal y, además, distingue mayúsculas y minúsculas según la colación. Si el delimitador es más de un carácter, debe coincidir exactamente; y si en tus datos el separador aparece a veces pegado y a veces con espacios, los resultados pueden no ser los que esperas.
Cuándo usar SUBSTRING_INDEX
SUBSTRING_INDEX es la mejor opción para dividir cadenas por un delimitador conocido: emails, dominios, nombres, rutas o líneas CSV sencillas. Cuando el corte depende de una posición numérica y no de un separador, SUBSTRING es lo adecuado; y para sustituir texto en lugar de extraerlo, la herramienta es REPLACE.
En el siguiente artículo veremos REPLACE, que sustituye todas las apariciones de un texto dentro de una cadena.
Escrito por Eduardo Lázaro
