MySQL 复杂字符串匹配

Posted

技术标签:

【中文标题】MySQL 复杂字符串匹配【英文标题】:MySQL complex string matching 【发布时间】:2017-12-25 07:53:47 【问题描述】:

我有一个 mysql 表,我在其中存储带有 PartNumber 字段的行,用于存储来自不同公司的库存数据。公司有不同的方式来传达相同的 PartNumber。

例如,假设我们有 PartNumber ROF-137-7516。同一部分可能具有该 PartNumber 的以下迭代:

ROF1377516
ROF1377516/R2
ROF 137 7516-2
ROF 137 7516/1
ROF 137 7516/1 R3D
ROF137 7516/2
ROF1377516/1
ROF-137-7516/2

我想要一个在用户输入“ROF-137-7516”搜索词时获取所有这些部分的查询。这是目前我的查询...

select * from parts where PartNumber like 'ROF-137-7516%';

但这只会返回最后一行。是否可以编写一个返回所有部分的查询?

【问题讨论】:

【参考方案1】:

如果你想在 SQL 中处理这个问题,这是REPLACE() 的一种方法:

SELECT *
FROM Parts
WHERE REPLACE(REPLACE(PartNumber,'-',''),' ','') LIKE REPLACE('ROF-137-7516%','-','')

这假设他们将始终输入带有- 或不带空格的PartNumber

【讨论】:

请记住,直接查询 PartNumber 将使用索引(如果存在),但查询 REPLACE(PartNumber, [...]) 将意味着优化器将不再能够使用索引(因为您不是实际比较索引中的 PartNumber 值,而是一些动态生成的数据)。 谢谢。不完美,但绝对比我迄今为止想出的任何东西都要好。 我稍微调整了你的 where 子句,这样即使他们输入带有空格的 PartNumber,我仍然会得到正确的匹配。 REPLACE(REPLACE(partNumber,'-',''),' ','') LIKE REPLACE(REPLACE('$partNumber%','-',''),' ','') 肯定慢一点,但它仍然足够快,可以作为一个可接受的解决方案。【参考方案2】:

您可能希望通过几种方法来执行此操作,具体取决于列中的数据,以及您需要什么样的性能才能摆脱表格。有关详细信息,请参阅 MySQL pattern matching 页面。


1) 根据您在 PartNumber 中可以预期的值,您可以将破折​​号替换为 % 通配符,以匹配 0 个或多个任意字符:

select * from parts where PartNumber like 'ROF%137%7516%'

但这对您来说可能还不够。例如,它会错误地返回具有以下值的行:ROF 123 137XX/7516


2) 如果您在 ROF 和其他数字之间总是有一些字符,那么您可以在搜索模式中使用 _

select * from parts where PartNumber like 'ROF_137_7516%'

但是,该匹配要求值之间恰好有一个字符,因此它不会匹配ROF1377516,也不会匹配ROF - 137 7516


3.1) 运行查询的最准确方法是使用正则表达式。但是,正则表达式会极大地影响您的性能;所以要谨慎使用它。在您的情况下,您使用.* 匹配任何字符(. 次或多次(*):

select * from parts where PartNumber regexp 'ROF.*137.*7516.*'

您可能会发现在 7516 中的 137 之前匹配“无限”个字符太多了。例如,它会错误地匹配:ROF 123 137XX/7516。您可能已经注意到,这与上面的 #1 完全相同。


3.2) 如果.* / % 太宽泛,那么您可以限制. 匹配的字符数。假设数字之间有一个字符(空格、破折号等)是标准的,但您希望考虑到用户错误(例如没有分隔字符,或键入两个分隔字符而不是一个)。您可以使用0,# 来限制要匹配的字符数。假设 0 到 2 个字符:

select * from parts where PartNumber regexp 'ROF.0,2137.0,27516.*'

这样,它将匹配您问题中的所有示例模式,但不会匹配 ROF 123 137XX/7516(因为“123”和“xx/”超过 2 个字符)


4) Aaron Dietz 回答了另一种技术,即使用 replace() 函数。根据您的表,这可能对您有用,但请记住,它将不再使用索引。表上的索引是针对列的原始值和数据类型的,但是通过 replace() 运行值将意味着索引值不能用于比较。

【讨论】:

以上是关于MySQL 复杂字符串匹配的主要内容,如果未能解决你的问题,请参考以下文章

REGEX 匹配整数 6 到 10

MySQL之正则表达式(REGEXP)

【算法笔记】字符串匹配

MySQL 查找子字符串匹配并按匹配全字分组

MySql学习笔记 —— 正则表达式的使用

Mysql之正则匹配