MySQL FIND_IN_SET Explicado: Como Pesquisar Valores Separados por Vírgula Corretamente

目次

1. Introdução

O Desafio de Pesquisar Dados Separados por Vírgulas no MySQL

Ao trabalhar com bancos de dados, você pode encontrar casos em que múltiplos valores são armazenados em uma única coluna separados por vírgulas. Por exemplo, uma coluna pode conter uma string como "1,3,5" e você pode querer extrair apenas os registros que incluam o valor “3”.

Nesses casos, usar o operador padrão = ou a cláusula IN frequentemente não produz os resultados esperados. Isso ocorre porque uma string separada por vírgulas é tratada como um único valor de string, ou seja, as comparações são avaliadas contra a string inteira em vez de elementos individuais dentro dela.

O Que é a Função FIND_IN_SET?

Em situações como esta, a função FIND_IN_SET do MySQL torna‑se muito útil.
Essa função permite determinar facilmente se um valor especificado existe dentro de uma string separada por vírgulas.

Por exemplo, considere a seguinte instrução SQL:

SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);

Nesta consulta, você pode extrair registros onde a string separada por vírgulas na coluna favorite_ids (por exemplo, "1,2,3,4") contém o valor “3”.

Propósito deste Artigo e Público‑Alvo

Este artigo explica como usar a função FIND_IN_SET desde o básico de forma clara e estruturada. Desde a sintaxe básica até exemplos práticos, comparações com outros métodos de busca, considerações importantes e FAQs, este guia fornece conhecimento prático para desenvolvimento no mundo real.

Este artigo destina‑se a:

  • Engenheiros web e desenvolvedores backend que utilizam MySQL regularmente
  • Desenvolvedores que precisam trabalhar com sistemas existentes que armazenam dados separados por vírgulas
  • Iniciantes em SQL que têm dificuldade com correspondência parcial e buscas baseadas em valores

2. Sintaxe Básica e Comportamento da Função FIND_IN_SET

Sintaxe do FIND_IN_SET

FIND_IN_SET é uma função do MySQL usada para determinar se um valor específico existe dentro de uma string separada por vírgulas. A sintaxe básica é a seguinte:

FIND_IN_SET(search_value, comma_separated_string)

Por exemplo:

SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3

Neste exemplo, como “3” aparece na terceira posição, a função retorna o valor numérico 3.

Regras de Valor de Retorno

A função FIND_IN_SET se comporta de acordo com as seguintes regras:

ConditionResult
The search value exists in the listIts position in the list (starting from 1)
The search value does not exist0
Either argument is NULLNULL

Exemplo (Retornando a Posição)

SELECT FIND_IN_SET('b', 'a,b,c'); -- Result: 2

Exemplo (Valor Não Encontrado)

SELECT FIND_IN_SET('d', 'a,b,c'); -- Result: 0

Exemplo (Inclui NULL)

SELECT FIND_IN_SET(NULL, 'a,b,c'); -- Result: NULL

Exemplo de Uso em uma Cláusula WHERE

Esta função é mais comumente usada para filtragem dentro de uma cláusula WHERE.

SELECT * FROM users WHERE FIND_IN_SET('admin', roles);

Neste exemplo, somente linhas onde a coluna roles contém a string “admin” serão retornadas. Se a coluna contiver um valor como "user,editor,admin", haverá correspondência.

Observações Importantes sobre Números e Strings

FIND_IN_SET realiza comparações como strings, o que significa que se comporta da seguinte forma:

SELECT FIND_IN_SET(3, '1,2,3,4');     -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4');   -- Result: 3

Embora funcione tanto com valores numéricos quanto com strings, tipos de dados pouco claros podem levar a comportamentos inesperados. Portanto, a melhor prática é tratar os valores explicitamente como strings sempre que possível.

3. Exemplos Práticos

Pesquisando em uma Coluna que Armazena Strings Separadas por Vírgulas

Em sistemas reais, você pode encontrar casos em que múltiplos valores (como IDs ou permissões) são armazenados em uma única coluna como uma string separada por vírgulas. Por exemplo, considere a seguinte tabela users.

idnamefavorite_ids
1Taro1,3,5
2Hanako2,4,6
3Jiro3,4,5

Quando você quiser “recuperar usuários que incluam 3”, a função FIND_IN_SET é extremamente conveniente.

SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);

Executar este SQL retornará os registros de “Taro” e “Jiro”.

Funciona Bem Mesmo Quando os Valores Parecem Numéricos

Mesmo quando favorite_ids parece conter números, FIND_IN_SET realiza comparações baseadas em strings, por isso é mais seguro passar o argumento como uma string com aspas.

-- 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 manter as consultas legíveis e o comportamento previsível, recomenda-se especificar explicitamente o valor como uma string.

Buscas Dinâmicas (Placeholders e Variáveis)

Ao gerar SQL dinamicamente a partir de um aplicativo web, é comum usar variáveis ou parâmetros vinculados.

Se você usar uma variável do MySQL, ficará assim:

SET @target_id = '3';
SELECT * FROM users WHERE FIND_IN_SET(@target_id, favorite_ids);

Ao vincular da camada de aplicativo (como PHP, Python ou Node.js), você pode lidar de forma semelhante usando placeholders.

Como Lidar com a Busca por Múltiplos Valores

Infelizmente, FIND_IN_SET pode buscar apenas um valor por vez.
Se você quiser recuperar registros que contenham “3 ou 4”, deve escrevê-lo várias vezes usando OR.

SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids) OR FIND_IN_SET('4', favorite_ids);

Se as condições se tornarem mais complexas, você deve construir o SQL dinamicamente em seu aplicativo ou considerar migrar para uma estrutura de tabela normalizada.

4. Comparando FIND_IN_SET com Outros Métodos de Busca

Alternativas Comuns: IN e LIKE

No MySQL, além de FIND_IN_SET, você também pode ver a cláusula IN ou a cláusula LIKE usada para verificar se um valor está incluído. No entanto, cada método se comporta de forma diferente, e usar o errado pode resultar em resultados de consulta incorretos.

Aqui, vamos esclarecer como eles diferem do FIND_IN_SET e quando usar cada abordagem.

Comparação com a Cláusula IN

A cláusula IN é tipicamente usada para verificar se um valor corresponde a um de vários valores constantes.

-- Example of IN (this does NOT search inside "favorite_ids" for the value 3)
SELECT * FROM users WHERE favorite_ids IN ('3');

Neste caso, apenas os registros onde favorite_ids é uma correspondência exata para “3” serão retornados. Isso significa que valores como "1,3,5" não corresponderão — apenas uma linha onde o valor da coluna é exatamente "3" corresponderá.

Em contraste, FIND_IN_SET verifica a posição de um elemento dentro de uma lista separada por vírgulas, permitindo que você recupere com precisão os registros que incluem “3” assim:

SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);

Diretriz de uso principal:

  • IN : Use com tabelas normalizadas (ex.: SELECT * FROM posts WHERE category_id IN (1, 3, 5) )
  • FIND_IN_SET : Use com strings separadas por vírgulas desnormalizadas

Comparação com a Cláusula LIKE

Tecnicamente, você pode usar LIKE para correspondência parcial, mas isso vem com armadilhas importantes.

-- A common mistake with LIKE
SELECT * FROM users WHERE favorite_ids LIKE '%3%';

Esta consulta não significa verdadeiramente “contém o valor 3” — ela corresponde a qualquer string que contenha o caractere “3”, o que significa que pode corresponder incorretamente a "13", "23" ou "30".

Isso torna impossível detectar de forma confiável se 3 existe como um valor independente.

Diretriz de uso principal:

  • LIKE : Útil para buscas de texto difusas, mas não pode reconhecer limites separados por vírgulas
  • FIND_IN_SET : Verifica com precisão as correspondências de valores independentes dentro de listas separadas por vírgulas

Diferenças de Desempenho

MethodUses IndexSearch TargetSpeed
INYesNumber or single value◎ Very fast
LIKEDepends on patternText scan△ Can become slow depending on conditions
FIND_IN_SETNoFull scan× May be slow

Em particular, FIND_IN_SET não pode usar índices e frequentemente aciona varreduras completas de tabela. Se você estiver trabalhando com conjuntos de dados grandes, pode precisar repensar o esquema.

5. Notas Importantes e Melhores Práticas

Não Compatível com Valores Contendo Vírgulas

A função FIND_IN_SET assume uma lista simples de valores separados por vírgulas. Portanto, se um elemento individual na lista contiver uma vírgula, a função não se comportará como esperado.

Exemplo Incorreto:

SELECT FIND_IN_SET('1,2', '1,2,3,4'); -- Result: 1

Usá‑la dessa forma pode produzir correspondências incorretas porque a string inteira é avaliada de forma inadequada.
Você só deve usar essa função quando puder garantir que valores individuais não contenham vírgulas.

Preocupações de Desempenho

Como o FIND_IN_SET não pode usar índices, ele realiza uma varredura completa da tabela. Como resultado, quando usado em tabelas grandes, o desempenho da consulta pode degradar‑se significativamente.

Soluções Alternativas:

  • Em vez de armazenar valores separados por vírgulas, normalize o relacionamento e gerencie‑lo em uma tabela separada.
  • Em ambientes críticos de desempenho, considere expansão de tabelas temporárias ou estratégias baseadas em JOIN .

Por exemplo, se você criar uma tabela intermediária como user_favorites, pode aproveitar os índices para buscas mais rápidas:

SELECT users.*
FROM users
JOIN user_favorites ON users.id = user_favorites.user_id
WHERE user_favorites.favorite_id = 3;

Legibilidade e Manutenibilidade

Embora o FIND_IN_SET possa parecer conveniente, ele traz várias desvantagens:

  • As consultas não são intuitivas (ela retorna valores de posição)
  • Adicionar ou remover valores é trabalhoso
  • A integridade dos dados é difícil de garantir (múltiplos significados em uma única coluna)

Portanto, quando a manutenibilidade e a integridade dos dados são importantes, revisar o próprio esquema costuma ser a melhor prática.

Quando Você Deve Usar FIND_IN_SET

Existem situações em que você não tem escolha a não ser trabalhar com colunas separadas por vírgulas — como sistemas legados ou produtos de terceiros. Nesses casos, considere as seguintes precauções:

  • Aplique outras condições de filtragem primeiro para reduzir o escopo da busca
  • Previna erros de formatação como vírgulas duplas ou espaços no início/fim
  • Execute processamento suplementar na camada de aplicação quando possível

6. Perguntas Frequentes (FAQ)

O FIND_IN_SET Pode Usar Índices?

Não, FIND_IN_SET não pode usar índices. Internamente, ele divide e avalia a string, portanto não se beneficia da otimização de índices do MySQL.

Como resultado, usá‑lo em tabelas grandes pode reduzir o desempenho das consultas. Para sistemas críticos de desempenho, considere redesenhar o esquema ou normalizar os dados.

Funciona Corretamente com Números e Strings Misturados?

Geralmente, sim — mas tenha em mente que as comparações são realizadas como strings. Se valores numéricos e de string forem misturados, pode ocorrer comportamento inesperado.

Por exemplo, ambos os seguintes retornam uma correspondência para 3:

SELECT FIND_IN_SET(3, '1,2,3,4');     -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4');   -- Result: 3

Contudo, em casos como FIND_IN_SET('03', '01,02,03'), a formatação com zero à esquerda pode afetar o comportamento da correspondência.
É mais seguro padronizar a formatação dos valores.

Como Posso Buscar Vários Valores de Uma Vez?

Como o FIND_IN_SET aceita apenas um único valor de busca, se você quiser buscar registros contendo “3 ou 4”, deve chamá‑lo várias vezes usando OR:

SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids)
   OR FIND_IN_SET('4', favorite_ids);

Se as condições se tornarem mais complexas, considere construir dinamicamente o SQL na camada de aplicação ou migrar para uma estrutura de tabela normalizada.

O FIND_IN_SET Está Causando Problemas de Desempenho. O Que Devo Fazer?

As estratégias a seguir são eficazes:

  • Mudar para um design de tabela normalizado
  • Aplicar condições de filtragem primeiro para reduzir o escopo da busca
  • Usá‑lo apenas ao lidar com pequenos conjuntos de dados
  • Considerar migração para formatos estruturados como busca full‑text ou tipos de dados JSON

Versões modernas do MySQL suportam tipos de dados JSON. Por exemplo, se você gerenciar a coluna roles como um array JSON, pode usar JSON_CONTAINS() para buscas flexíveis e eficientes.

O FIND_IN_SET será descontinuado no futuro?

A partir do MySQL 8.0, FIND_IN_SET não está oficialmente depreciado. No entanto, estruturas de dados desnormalizadas (colunas separadas por vírgulas) não são recomendadas, portanto o uso prático desta função deve diminuir ao longo do tempo.

Ao redesenhar seu banco de dados, é ideal adotar estruturas normalizadas ou designs baseados em JSON.

7. Conclusão

Revisando os recursos e vantagens do FIND_IN_SET

A função FIND_IN_SET é extremamente útil no MySQL ao pesquisar strings separadas por vírgulas. É especialmente útil quando você precisa extrair registros que contêm um valor específico dentro de uma única coluna que armazena múltiplos valores.

Com sua sintaxe simples, permite verificações de correspondência de valores isolados que são difíceis de alcançar com precisão usando as cláusulas LIKE ou IN. Essa capacidade de detectar elementos distintos dentro de uma lista separada por vírgulas é sua maior força.

Considerações importantes ao usá‑lo

Ao mesmo tempo, há várias limitações e considerações importantes, portanto não deve ser usado em excesso sem reflexão cuidadosa:

  • Índices não podem ser usados (o que pode tornar as buscas mais lentas)
  • Não é compatível com valores que contêm vírgulas
  • Presume uma estrutura desnormalizada
  • Suporta apenas buscas de valor único (buscas múltiplas requerem condições OR)

Compreender essas características é essencial para usar a função adequadamente.

Quando você deve — e não deve — usá‑lo

SituationShould You Use It?Reason
Small dataset, infrequent searches✅ YesEasy to implement and low development cost
Dependent on a legacy system structure✅ Use selectivelyUseful when refactoring is difficult
Large dataset, high-frequency access❌ Not recommendedPerformance degradation becomes significant
Schema can be normalized❌ AvoidJOINs or intermediate tables are more efficient

Como aplicar isso na prática

  • Entenda‑a como uma ferramenta flexível para trabalhar dentro das estruturas de banco de dados existentes
  • Use‑a como ponto de referência ao decidir se deve adotar um design de dados normalizado no futuro
  • Em vez de usá‑la como uma solução rápida, compreenda claramente o que a função realmente faz

Para desenvolvedores que priorizam manutenibilidade e legibilidade, é melhor pensar nisso como uma função que você pode “usar temporariamente—mas eventualmente deixar de usar.”