Em primeiro lugar, considere armazenar os dados de maneira normalizada. Aqui está uma boa leitura:Armazenar uma lista delimitada em uma coluna de banco de dados é tão ruim assim?
Agora - Assumindo o seguinte esquema e dados:
create table products (
id int auto_increment,
upc varchar(50),
upc_variation text,
primary key (id),
index (upc)
);
insert into products (upc, upc_variation) values
('01234', '01234,12345,23456'),
('56789', '45678,34567'),
('056789', '045678,034567');
Queremos encontrar produtos com variações
'12345'
e '34567'
. O resultado esperado é a 1ª e a 2ª linhas. Esquema normalizado - relação muitos-para-muitos
Em vez de armazenar os valores em uma lista separada por vírgulas, crie uma nova tabela, que mapeia IDs de produtos com variações:
create table products_upc_variations (
product_id int,
upc_variation varchar(50),
primary key (product_id, upc_variation),
index (upc_variation, product_id)
);
insert into products_upc_variations (product_id, upc_variation) values
(1, '01234'),
(1, '12345'),
(1, '23456'),
(2, '45678'),
(2, '34567'),
(3, '045678'),
(3, '034567');
A consulta de seleção seria:
select distinct p.*
from products p
join products_upc_variations v on v.product_id = p.id
where v.upc_variation in ('12345', '34567');
Como você vê - Com um esquema normalizado, o problema pode ser resolvido com uma consulta bastante básica. E podemos efetivamente usar índices.
"Explorando" um ÍNDICE DE TEXTO COMPLETO
Com um FULLTEXT INDEX em
(upc_variation)
você pode usar:select p.*
from products p
where match (upc_variation) against ('12345 34567');
Isso parece bastante "bonito" e provavelmente é eficiente. Mas embora funcione para este exemplo, não me sentiria confortável com esta solução, porque não posso dizer exatamente quando não funciona.
Usando JSON_OVERLAPS()
Desde o MySQL 8.0.17 você pode usar JSON_OVERLAPS() . Você deve armazenar os valores como uma matriz JSON ou converter a lista em JSON "on the fly":
select p.*
from products p
where json_overlaps(
'["12345","34567"]',
concat('["', replace(upc_variation, ',', '","'), '"]')
);
Nenhum índice pode ser usado para isso. Mas também não pode para
FIND_IN_SET()
. Usando JSON_TABLE()
Desde o MySQL 8.0.4 você pode usar JSON_TABLE() para gerar uma representação normalizada dos dados "on the fly". Aqui, novamente, você armazenaria os dados em uma matriz JSON ou converteria a lista em JSON na consulta:
select distinct p.*
from products p
join json_table(
concat('["', replace(p.upc_variation, ',', '","'), '"]'),
'$[*]' columns (upcv text path '$')
) v
where v.upcv in ('12345', '34567');
Nenhum índice pode ser usado aqui. E esta é provavelmente a solução mais lenta de todas apresentadas nesta resposta.
RLIKE / REGEXP
Você também pode usar uma expressão regular :
select p.*
from products p
where p.upc_variation rlike '(^|,)(12345|34567)(,|$)'
Veja demonstração de todas as consultas em dbfiddle.uk