REGEXP
El operador REGEXP permite filtrar filas en una cláusula WHERE usando expresiones regulares. Es la forma más directa de aplicar patrones regulares en MySQL y, junto con su sinónimo RLIKE, constituye la puerta de entrada al uso de expresiones regulares en consultas SQL.
Cuando LIKE se queda corto porque necesitas buscar patrones complejos como dígitos, alternativas, repeticiones o formatos específicos, REGEXP es la herramienta adecuada.
Sintaxis
expresion REGEXP patron
-- Sinónimo (idéntico comportamiento)
expresion RLIKE patron
-- Negación
expresion NOT REGEXP patron
expresion NOT RLIKE patronEl operador devuelve 1 si la expresión coincide con el patrón, 0 si no coincide y NULL si alguno de los operandos es NULL. A diferencia de LIKE, que exige que el patrón coincida con la cadena completa, REGEXP devuelve coincidencia si el patrón se encuentra en cualquier parte de la cadena. Si necesitas que coincida con toda la cadena, debes usar las anclas ^ y $.
Comportamiento básico
Comencemos con un ejemplo sencillo. Supón que tienes una tabla productos y quieres encontrar todos los que contienen la palabra "Pro" en su nombre:
SELECT nombre, precio
FROM productos
WHERE nombre REGEXP 'Pro';| nombre | precio |
|---|---|
| iPhone 15 Pro | 1299.99 |
| iPhone 15 Pro Max | 1499.99 |
| MacBook Pro 16 | 2499.00 |
| iPad Pro 12.9 | 1199.00 |
Esto podría lograrse con LIKE '%Pro%', pero la ventaja de REGEXP aparece cuando los patrones se complican. Por ejemplo, buscar productos cuyo nombre contenga un número seguido de una unidad de medida:
SELECT nombre, precio
FROM productos
WHERE nombre REGEXP '[0-9]+(GB|TB|MHz|W|mm)';| nombre | precio |
|---|---|
| SSD Samsung 1TB | 109.99 |
| RAM DDR5 32GB | 89.99 |
| Cargador USB-C 65W | 35.99 |
| Monitor 27" 144MHz | 349.00 |
Este patrón busca uno o más dígitos seguidos de una de las unidades listadas. Expresar esto con LIKE requeriría múltiples condiciones OR, y aun así no podrías asegurar que los dígitos están justo antes de la unidad.
RLIKE como sinónimo
RLIKE es un sinónimo exacto de REGEXP. MySQL lo incluye por compatibilidad con otros sistemas de bases de datos. Ambos producen exactamente el mismo resultado:
-- Estas dos consultas son idénticas
SELECT nombre FROM productos WHERE nombre REGEXP '^Mac';
SELECT nombre FROM productos WHERE nombre RLIKE '^Mac';Elige el que te resulte más legible. En la documentación oficial y en la comunidad MySQL, REGEXP es el más utilizado.
Sensibilidad a mayúsculas y minúsculas
Por defecto, REGEXP en MySQL es insensible a mayúsculas y minúsculas cuando la collation de la columna es case-insensitive (que es el caso habitual con utf8mb4_0900_ai_ci):
SELECT nombre FROM productos WHERE nombre REGEXP 'iphone';| nombre |
|---|
| iPhone 15 Pro |
| iPhone 15 Pro Max |
| iPhone 14 |
Aunque el patrón está en minúsculas, coincide con "iPhone" porque la comparación es case-insensitive. Si necesitas forzar una comparación sensible a mayúsculas, usa la palabra clave BINARY:
-- Sensible a mayúsculas: 'iphone' NO coincide con 'iPhone'
SELECT nombre FROM productos WHERE nombre REGEXP BINARY 'iphone';Esta consulta no devuelve resultados porque ningún nombre tiene "iphone" exactamente en minúsculas. Si cambias el patrón a 'iPhone', sí encontrarás coincidencias.
SELECT nombre FROM productos WHERE nombre REGEXP BINARY 'iPhone';| nombre |
|---|
| iPhone 15 Pro |
| iPhone 15 Pro Max |
| iPhone 14 |
NOT REGEXP
La negación NOT REGEXP es fundamental para encontrar filas que no cumplen un patrón. Esto es especialmente útil para detectar datos que no se ajustan al formato esperado:
-- Encontrar productos sin código de referencia válido
SELECT nombre, referencia
FROM productos
WHERE referencia NOT REGEXP '^[A-Z]{2,3}-[0-9]{3,5}$';| nombre | referencia |
|---|---|
| Producto de prueba | test |
| Oferta especial | NULL |
| Cable genérico | 12345 |
La consulta identifica productos cuya referencia no sigue el formato estándar de dos o tres letras mayúsculas, un guion y de tres a cinco dígitos.
Caso práctico: validar emails
Uno de los usos más habituales de REGEXP es validar formatos de datos. Para filtrar clientes con emails que parecen válidos:
SELECT nombre, email
FROM clientes
WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$';| nombre | |
|---|---|
| María García | maria.garcia@gmail.com |
| Carlos López | carlos.lopez@empresa.es |
| Ana Martínez | a.martinez+trabajo@outlook.com |
Y para encontrar los que tienen emails potencialmente inválidos:
SELECT nombre, email
FROM clientes
WHERE email NOT REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
OR email IS NULL;| nombre | |
|---|---|
| Pedro Ruiz | pedro@@correo.com |
| Test User | no-es-un-email |
| Laura Vega | NULL |
Recuerda que REGEXP devuelve NULL cuando algún operando es NULL, y NOT NULL sigue siendo NULL, por lo que necesitas la condición OR email IS NULL explícita para capturar esos casos.
Caso práctico: buscar teléfonos por formato
Supón que tu tabla de clientes almacena teléfonos en distintos formatos y necesitas encontrar los que siguen el patrón español:
-- Teléfonos móviles españoles: empiezan por 6 o 7, 9 dígitos total
SELECT nombre, telefono
FROM clientes
WHERE telefono REGEXP '^(\\+34)?[67][0-9]{8}$';| nombre | telefono |
|---|---|
| María García | 612345678 |
| Carlos López | +34678901234 |
| Ana Martínez | 712345678 |
-- Teléfonos fijos españoles: empiezan por 9, 9 dígitos total
SELECT nombre, telefono
FROM clientes
WHERE telefono REGEXP '^(\\+34)?9[0-9]{8}$';| nombre | telefono |
|---|---|
| Pedro Ruiz | 912345678 |
| Laura Vega | +34934567890 |
Estos patrones te permiten segmentar fácilmente los clientes según el tipo de teléfono que han proporcionado.
Caso práctico: buscar códigos de producto
En un sistema de inventario, los productos suelen tener códigos con formatos específicos según la categoría. Con REGEXP puedes buscar por patrones de código:
-- Productos de electrónica: código empieza por ELE seguido de 4 dígitos
SELECT nombre, codigo, precio
FROM productos
WHERE codigo REGEXP '^ELE-[0-9]{4}$';| nombre | codigo | precio |
|---|---|---|
| iPhone 15 Pro | ELE-0012 | 1299.99 |
| Samsung Galaxy S24 | ELE-0025 | 899.99 |
| MacBook Air M3 | ELE-0108 | 1399.00 |
-- Buscar productos de cualquier categoría con código de 4+ dígitos
SELECT nombre, codigo
FROM productos
WHERE codigo REGEXP '^[A-Z]{2,4}-[0-9]{4,}$'
ORDER BY codigo;| nombre | codigo |
|---|---|
| Camiseta algodón | ROP-1001 |
| Pantalón vaquero | ROP-1025 |
| Balón fútbol | DEP-2001 |
| iPhone 15 Pro | ELE-0012 |
| Sartén antiadherente | HOG-3010 |
Caso práctico: validar códigos postales
Distintos países tienen formatos de código postal diferentes. Con REGEXP puedes validar según el país:
SELECT
nombre,
pais,
codigo_postal,
CASE
WHEN pais = 'España' AND codigo_postal REGEXP '^[0-5][0-9]{4}$' THEN 'Válido'
WHEN pais = 'México' AND codigo_postal REGEXP '^[0-9]{5}$' THEN 'Válido'
WHEN pais = 'Argentina' AND codigo_postal REGEXP '^[A-Z][0-9]{4}[A-Z]{3}$' THEN 'Válido'
ELSE 'Revisar'
END AS estado_cp
FROM clientes;| nombre | pais | codigo_postal | estado_cp |
|---|---|---|---|
| María García | España | 28001 | Válido |
| Juan Pérez | México | 06600 | Válido |
| Roberto Silva | Argentina | C1425DKE | Válido |
| Laura Díaz | España | 99001 | Revisar |
El código postal 99001 no es válido en España porque las provincias españolas van del 01 al 52, y el primer dígito no puede ser mayor que 5.
Manejo de NULL
Cuando la expresión o el patrón son NULL, REGEXP devuelve NULL en lugar de 0 o 1. Esto es consistente con el comportamiento de SQL ante valores nulos, pero puede causar resultados inesperados si no lo tienes en cuenta:
SELECT
nombre,
telefono,
telefono REGEXP '^[0-9]+$' AS es_numerico
FROM clientes;| nombre | telefono | es_numerico |
|---|---|---|
| María García | 612345678 | 1 |
| Carlos López | +34678901234 | 0 |
| Pedro Ruiz | NULL | NULL |
Para Pedro Ruiz, el resultado es NULL, no 0. Si usas esta expresión en un WHERE, las filas con NULL no se incluirán ni con REGEXP ni con NOT REGEXP. Si necesitas incluirlas, maneja el NULL explícitamente:
SELECT nombre, telefono
FROM clientes
WHERE telefono REGEXP '^[0-9]+$'
OR telefono IS NULL;Combinación con otras funciones
REGEXP se combina frecuentemente con CASE, IF y funciones de agregación para analizar datos:
-- Contar clientes por tipo de email
SELECT
COUNT(*) AS total,
SUM(IF(email REGEXP '@gmail\\.com$', 1, 0)) AS gmail,
SUM(IF(email REGEXP '@(outlook|hotmail)\\.com$', 1, 0)) AS microsoft,
SUM(IF(email REGEXP '@yahoo\\.(com|es)$', 1, 0)) AS yahoo,
SUM(IF(email NOT REGEXP '@(gmail|outlook|hotmail|yahoo)\\.', 1, 0)) AS otros
FROM clientes
WHERE email IS NOT NULL;| total | gmail | microsoft | yahoo | otros |
|---|---|---|---|---|
| 248 | 95 | 67 | 31 | 55 |
Esta consulta genera un resumen de los proveedores de email de tus clientes en una sola pasada, algo que sería mucho más verboso con condiciones LIKE.
-- Agrupar productos por patrón de código
SELECT
CASE
WHEN codigo REGEXP '^ELE-' THEN 'Electrónica'
WHEN codigo REGEXP '^ROP-' THEN 'Ropa'
WHEN codigo REGEXP '^HOG-' THEN 'Hogar'
WHEN codigo REGEXP '^DEP-' THEN 'Deportes'
ELSE 'Otros'
END AS categoria,
COUNT(*) AS cantidad,
ROUND(AVG(precio), 2) AS precio_medio
FROM productos
GROUP BY categoria
ORDER BY cantidad DESC;| categoria | cantidad | precio_medio |
|---|---|---|
| Electrónica | 45 | 687.50 |
| Ropa | 38 | 45.20 |
| Hogar | 25 | 89.30 |
| Deportes | 18 | 62.75 |
| Otros | 12 | 33.90 |
En el siguiente artículo veremos REGEXP_LIKE como la función equivalente con opciones adicionales.
Escrito por Eduardo Lázaro
