1. Introducción
El desafío de buscar datos separados por comas en MySQL
Al trabajar con bases de datos, puede encontrarse con casos en los que varios valores se almacenan en una sola columna separados por comas. Por ejemplo, una columna puede contener una cadena como "1,3,5", y es posible que desee extraer solo los registros que incluyan el valor «3».
En tales casos, usar el operador estándar = o la cláusula IN a menudo no produce los resultados esperados. Esto se debe a que una cadena separada por comas se trata como un único valor de cadena, lo que significa que las comparaciones se evalúan contra la cadena completa en lugar de contra los elementos individuales que contiene.
Qué es la función FIND_IN_SET?
En situaciones como esta, la función FIND_IN_SET de MySQL resulta muy útil.
Esta función le permite determinar fácilmente si un valor especificado existe dentro de una cadena separada por comas.
Por ejemplo, considere la siguiente sentencia SQL:
SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);
En esta consulta, puede extraer los registros donde la cadena separada por comas en la columna favorite_ids (p. ej., "1,2,3,4") contiene el valor «3».
Propósito de este artículo y público objetivo
Este artículo explica cómo usar la función FIND_IN_SET desde lo básico de manera clara y estructurada. Desde la sintaxis básica hasta ejemplos prácticos, comparaciones con otros métodos de búsqueda, consideraciones importantes y preguntas frecuentes, esta guía brinda conocimientos prácticos para el desarrollo real.
Este artículo está dirigido a:
- Ingenieros web y desarrolladores backend que utilizan MySQL de forma regular
- Desarrolladores que deben trabajar con sistemas existentes que almacenan datos separados por comas
- Principiantes en SQL que tienen dificultades con coincidencias parciales y búsquedas basadas en valores
2. Sintaxis básica y comportamiento de la función FIND_IN_SET
Sintaxis de FIND_IN_SET
FIND_IN_SET es una función de MySQL que se utiliza para determinar si un valor específico existe dentro de una cadena separada por comas. La sintaxis básica es la siguiente:
FIND_IN_SET(search_value, comma_separated_string)
Por ejemplo:
SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3
En este ejemplo, como «3» aparece en la tercera posición, la función devuelve el valor numérico 3.
Reglas del valor de retorno
La función FIND_IN_SET se comporta según las siguientes reglas:
| Condition | Result |
|---|---|
| The search value exists in the list | Its position in the list (starting from 1) |
| The search value does not exist | 0 |
| Either argument is NULL | NULL |
Ejemplo (Posición devuelta)
SELECT FIND_IN_SET('b', 'a,b,c'); -- Result: 2
Ejemplo (Valor no encontrado)
SELECT FIND_IN_SET('d', 'a,b,c'); -- Result: 0
Ejemplo (NULL incluido)
SELECT FIND_IN_SET(NULL, 'a,b,c'); -- Result: NULL
Ejemplo de uso en una cláusula WHERE
Esta función se usa con mayor frecuencia para filtrar dentro de una cláusula WHERE.
SELECT * FROM users WHERE FIND_IN_SET('admin', roles);
En este ejemplo, solo se devolverán las filas donde la columna roles contenga la cadena «admin». Si la columna contiene un valor como "user,editor,admin", coincidirá.
Notas importantes sobre números y cadenas
FIND_IN_SET realiza comparaciones como cadenas, lo que significa que se comporta de la siguiente manera:
SELECT FIND_IN_SET(3, '1,2,3,4'); -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3
Aunque funciona con valores numéricos y de cadena, los tipos de datos poco claros pueden generar comportamientos inesperados. Por lo tanto, la mejor práctica es manejar los valores explícitamente como cadenas siempre que sea posible.
3. Ejemplos prácticos
Búsqueda en una columna que almacena cadenas separadas por comas
En sistemas reales, puede encontrar casos donde varios valores (como IDs o permisos) se almacenan en una sola columna como una cadena separada por comas. Por ejemplo, considere la siguiente tabla users.
| id | name | favorite_ids |
|---|---|---|
| 1 | Taro | 1,3,5 |
| 2 | Hanako | 2,4,6 |
| 3 | Jiro | 3,4,5 |
Cuando desea “recuperar usuarios que incluyan 3”, la función FIND_IN_SET resulta extremadamente conveniente.
SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);
Ejecutar este SQL devolverá los registros de “Taro” y “Jiro”.
Funciona bien incluso cuando los valores parecen numéricos
Incluso cuando favorite_ids parece contener números, FIND_IN_SET realiza comparaciones basadas en cadenas, por lo que lo más seguro es pasar el argumento como una cadena entre comillas.
-- OK
SELECT * FROM users WHERE FIND_IN_SET('5', favorite_ids);
-- Works, but strictly speaking not recommended
SELECT * FROM users WHERE FIND_IN_SET(5, favorite_ids);
Para que las consultas sean legibles y el comportamiento predecible, se recomienda especificar explícitamente el valor como una cadena.
Búsquedas dinámicas (Marcadores de posición y variables)
Al generar SQL de forma dinámica desde una aplicación web, es común usar variables o parámetros enlazados.
Si utilizas una variable de MySQL, se ve así:
SET @target_id = '3';
SELECT * FROM users WHERE FIND_IN_SET(@target_id, favorite_ids);
Al enlazar desde la capa de la aplicación (como PHP, Python o Node.js), puedes manejarlo de forma similar usando marcadores de posición.
Cómo manejar la búsqueda de múltiples valores
Desafortunadamente, FIND_IN_SET solo puede buscar un valor a la vez.
Si deseas obtener registros que contengan “3 o 4”, debes escribirlo varias veces usando OR.
SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids) OR FIND_IN_SET('4', favorite_ids);
Si las condiciones se vuelven más complejas, deberías construir dinámicamente el SQL en tu aplicación o considerar migrar a una estructura de tabla normalizada.
4. Comparando FIND_IN_SET con otros métodos de búsqueda
Alternativas comunes: IN y LIKE
En MySQL, además de FIND_IN_SET, también puedes ver la cláusula IN o la cláusula LIKE usadas para comprobar si un valor está incluido. Sin embargo, cada método se comporta de manera diferente, y usar el incorrecto puede producir resultados de consulta incorrectos.
Aquí, aclararemos cómo difieren de FIND_IN_SET y cuándo usar cada enfoque.
Comparación con la cláusula IN
La cláusula IN se usa típicamente para comprobar si un valor coincide con uno de varios valores constantes.
-- Example of IN (this does NOT search inside "favorite_ids" for the value 3)
SELECT * FROM users WHERE favorite_ids IN ('3');
En este caso, solo se devolverán los registros donde favorite_ids sea una coincidencia exacta con “3”. Eso significa que valores como "1,3,5" no coincidirán; solo una fila donde el valor de la columna sea exactamente "3" coincidirá.
En cambio, FIND_IN_SET verifica la posición de un elemento dentro de una lista separada por comas, lo que permite recuperar con precisión los registros que incluyen “3” de la siguiente manera:
SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);
✅ Directriz clave de uso:
IN: Úsalo con tablas normalizadas (p. ej.,SELECT * FROM posts WHERE category_id IN (1, 3, 5))FIND_IN_SET: Úsalo con cadenas separadas por comas desnormalizadas
Comparación con la cláusula LIKE
Técnicamente, puedes usar LIKE para coincidencias parciales, pero conlleva importantes inconvenientes.
-- A common mistake with LIKE
SELECT * FROM users WHERE favorite_ids LIKE '%3%';
Esta consulta no significa realmente “contiene el valor 3”; coincide con cualquier cadena que contenga el carácter “3”, lo que puede hacer que coincida incorrectamente con "13", "23" o "30".
Esto hace imposible detectar de forma fiable si 3 existe como un valor independiente.
✅ Directriz clave de uso:
LIKE: Útil para búsquedas de texto difuso, pero no puede reconocer los límites de valores separados por comasFIND_IN_SET: Comprueba con precisión coincidencias de valores independientes dentro de listas separadas por comas
Diferencias de rendimiento
| Method | Uses Index | Search Target | Speed |
|---|---|---|---|
IN | Yes | Number or single value | ◎ Very fast |
LIKE | Depends on pattern | Text scan | △ Can become slow depending on conditions |
FIND_IN_SET | No | Full scan | × May be slow |
En particular, FIND_IN_SET no puede usar índices y a menudo provoca escaneos completos de tabla. Si trabajas con conjuntos de datos grandes, puede que necesites replantear el esquema.
5. Notas importantes y mejores prácticas
No compatible con valores que contengan comas
La función FIND_IN_SET asume una lista simple de valores separados por comas. Por lo tanto, si un elemento individual en la lista contiene una coma, la función no se comportará como se pretende.
Ejemplo incorrecto:
SELECT FIND_IN_SET('1,2', '1,2,3,4'); -- Result: 1
Usarlo de esta manera puede producir coincidencias incorrectas porque la cadena completa se evalúa de forma incorrecta.
Solo debe usar esta función cuando pueda garantizar que los valores individuales no contengan comas.
Problemas de rendimiento
Debido a que FIND_IN_SET no puede usar índices, realiza un escaneo completo de la tabla. Como resultado, cuando se usa en tablas grandes, el rendimiento de las consultas puede degradarse significativamente.
Soluciones alternativas:
- En lugar de almacenar valores separados por comas, normalice la relación y adminístrela en una tabla separada.
- En entornos críticos de rendimiento, considere la expansión de tablas temporales o estrategias basadas en JOIN .
Por ejemplo, si crea una tabla intermedia como user_favorites, puede aprovechar los índices para búsquedas más rápidas:
SELECT users.*
FROM users
JOIN user_favorites ON users.id = user_favorites.user_id
WHERE user_favorites.favorite_id = 3;
Legibilidad y mantenibilidad
Aunque FIND_IN_SET puede parecer conveniente, tiene varios inconvenientes:
- Las consultas no son intuitivas (devuelve valores de posición)
- Añadir o eliminar valores es engorroso
- La integridad de los datos es difícil de aplicar (múltiples significados en una sola columna)
Por lo tanto, cuando la mantenibilidad y la integridad de los datos son importantes, revisar el esquema mismo suele ser la mejor práctica.
Cuando debe usar FIND_IN_SET
Hay situaciones en las que no tiene más remedio que trabajar con columnas separadas por comas, como sistemas heredados o productos de terceros. En esos casos, considere las siguientes precauciones:
- Aplicar otras condiciones de filtrado primero para reducir el alcance de la búsqueda
- Prevenir errores de formato como comas dobles o espacios al inicio/final
- Realizar procesamiento suplementario en la capa de aplicación cuando sea posible
6. Preguntas frecuentes (FAQ)
¿Puede FIND_IN_SET usar índices?
No, FIND_IN_SET no puede usar índices. Internamente, divide y evalúa la cadena, por lo que no se beneficia de la optimización de índices de MySQL.
Como resultado, usarlo en tablas grandes puede ralentizar el rendimiento de las consultas. Para sistemas críticos de rendimiento, considere rediseñar el esquema o normalizar los datos.
¿Funciona correctamente con números y cadenas mezclados?
En general, sí, pero tenga en cuenta que las comparaciones se realizan como cadenas. Si se mezclan valores numéricos y de cadena, puede haber un comportamiento inesperado.
Por ejemplo, ambos de los siguientes devuelven una coincidencia para 3:
SELECT FIND_IN_SET(3, '1,2,3,4'); -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3
Sin embargo, en casos como FIND_IN_SET('03', '01,02,03'), el formato con ceros iniciales puede afectar el comportamiento de coincidencia.
Lo más seguro es estandarizar el formato de los valores.
¿Cómo puedo buscar varios valores a la vez?
Debido a que FIND_IN_SET solo acepta un único valor de búsqueda, si desea buscar registros que contengan “3 o 4”, debe llamarlo varias veces usando OR:
SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids)
OR FIND_IN_SET('4', favorite_ids);
Si las condiciones se vuelven más complejas, considere construir dinámicamente el SQL en la capa de aplicación o migrar a una estructura de tabla normalizada.
FIND_IN_SET está causando problemas de rendimiento. ¿Qué debo hacer?
Las siguientes estrategias son efectivas:
- Cambiar a un diseño de tabla normalizado
- Aplicar condiciones de filtrado primero para reducir el alcance de la búsqueda
- Usarlo solo cuando se trabaje con conjuntos de datos pequeños
- Considerar migrar a formatos estructurados como búsqueda de texto completo o tipos de datos JSON
Versiones modernas de MySQL admiten tipos de datos JSON. Por ejemplo, si gestionas la columna roles como un arreglo JSON, puedes usar JSON_CONTAINS() para búsquedas flexibles y eficientes.
¿Será FIND_IN_SET obsoleto en el futuro?
A partir de MySQL 8.0, FIND_IN_SET no está oficialmente en desuso. Sin embargo, las estructuras de datos desnormalizadas (columnas separadas por comas) no se recomiendan, por lo que se espera que el uso práctico de esta función disminuya con el tiempo.
Al rediseñar tu base de datos, lo ideal es adoptar estructuras normalizadas o diseños basados en JSON.
7. Conclusión
Revisión de las características y ventajas de FIND_IN_SET
La función FIND_IN_SET es extremadamente útil en MySQL al buscar cadenas separadas por comas. Resulta especialmente útil cuando necesitas extraer registros que contienen un valor específico dentro de una única columna que almacena varios valores.
Con su sintaxis simple, permite comprobar coincidencias de valores aislados que son difíciles de lograr con precisión mediante las cláusulas LIKE o IN. Esta capacidad de detectar elementos distintos dentro de una lista separada por comas es su mayor fortaleza.
Consideraciones importantes al usarla
Al mismo tiempo, existen varias limitaciones y consideraciones importantes, por lo que no debe usarse en exceso sin una reflexión cuidadosa:
- No se pueden usar índices (lo que puede ralentizar las búsquedas)
- No es compatible con valores que contengan comas
- Asume una estructura desnormalizada
- Solo admite búsquedas de un solo valor (las búsquedas múltiples requieren condiciones
OR)
Comprender estas características es esencial para utilizar la función de manera adecuada.
Cuándo deberías — y cuándo no deberías — usarla
| Situation | Should You Use It? | Reason |
|---|---|---|
| Small dataset, infrequent searches | ✅ Yes | Easy to implement and low development cost |
| Dependent on a legacy system structure | ✅ Use selectively | Useful when refactoring is difficult |
| Large dataset, high-frequency access | ❌ Not recommended | Performance degradation becomes significant |
| Schema can be normalized | ❌ Avoid | JOINs or intermediate tables are more efficient |
Cómo aplicar esto en la práctica
- Entenderla como una herramienta flexible para trabajar dentro de estructuras de bases de datos existentes
- Usarla como punto de referencia al decidir si adoptar un diseño de datos normalizado en el futuro
- En lugar de usarla como una solución rápida, comprender claramente qué hace realmente la función
Para los desarrolladores que priorizan la mantenibilidad y legibilidad, lo mejor es considerar esta función como algo que “se usa temporalmente, pero que eventualmente se debe dejar de usar”.


