首先考虑以规范化的方式存储数据。这是一篇很好的读物:在数据库列中存储分隔列表真的那么糟糕吗? https://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-that-bad
现在 - 假设以下架构和数据:
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');
我们希望找到具有变化的产品'12345'
and '34567'
。预期结果是第一行和第二行。
规范化模式 - 多对多关系
不要将值存储在逗号分隔的列表中,而是创建一个新表,该表将产品 ID 与变体进行映射:
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');
选择查询将是:
select distinct p.*
from products p
join products_upc_variations v on v.product_id = p.id
where v.upc_variation in ('12345', '34567');
正如您所看到的 - 使用规范化模式,可以通过非常基本的查询来解决问题。我们可以有效地利用指数。
“利用”全文索引
启用全文索引(upc_variation)
您可以使用:
select p.*
from products p
where match (upc_variation) against ('12345 34567');
这看起来相当“漂亮”并且可能很有效。但是,尽管它适用于这个示例,但我对此解决方案感到不舒服,因为我无法准确地说出它何时不起作用。
使用 JSON_OVERLAPS()
从 MySQL 8.0.17 开始你可以使用JSON_OVERLAPS() https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-overlaps。您应该将值存储为 JSON 数组,或者“即时”将列表转换为 JSON:
select p.*
from products p
where json_overlaps(
'["12345","34567"]',
concat('["', replace(upc_variation, ',', '","'), '"]')
);
没有索引可以用于此目的。但两者都不能为FIND_IN_SET()
.
使用 JSON_TABLE()
从 MySQL 8.0.4 开始你可以使用JSON_TABLE() https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html“即时”生成数据的标准化表示。同样,您可以将数据存储在 JSON 数组中,或者在查询中将列表转换为 JSON:
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');
这里不能使用索引。这可能是这个答案中提出的所有解决方案中最慢的解决方案。
类似/正则表达式
您还可以使用正则表达式 https://dev.mysql.com/doc/refman/8.0/en/regexp.html#operator_regexp:
select p.*
from products p
where p.upc_variation rlike '(^|,)(12345|34567)(,|$)'
See