MySQL 复杂字符串匹配
MySQL complex string matching
我有一个 MySQL table,我在其中存储带有 PartNumber 字段的行,用于来自不同公司的库存数据。公司有不同的方式来传达相同的 PartNumber。
例如,假设我们有零件号 ROF-137-7516。同一部件可能具有该部件号的以下迭代:
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%';
但那只是 returns 最后一行。是否可以编写 returns 所有部分的查询?
如果您想在 SQL 中处理此问题,这是 REPLACE()
的一种方法:
SELECT *
FROM Parts
WHERE REPLACE(REPLACE(PartNumber,'-',''),' ','') LIKE REPLACE('ROF-137-7516%','-','')
这假设他们将始终输入带 -
或没有空格的 PartNumber
。
您可能希望通过几种方式来执行此操作,具体取决于您的列中的数据,以及您需要从 table 中获得什么样的性能。有关详细信息,请参阅 MySQL pattern matching 页面。
1)
根据您在 PartNumber 中期望的值,您可以将破折号替换为 %
通配符,以匹配 0 个或多个任意字符:
select * from parts where PartNumber like 'ROF%137%7516%'
但这对您来说可能还不够。例如,它会错误地 return 具有此值的行: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 之前匹配 "infinite" 个字符太多了。例如,它会错误地匹配:ROF 123 137XX/7516
。您可能已经注意到这与上面的#1 完全相同。
3.2)
如果 .*
/ %
过于宽泛,那么您可以限制 .
匹配的字符数。假设在数字之间有一个字符(space、破折号等)是标准做法,但您要考虑到用户错误(例如没有分隔字符,或键入两个分隔字符而不是一个分隔字符)。您可以使用 {0,#}
来限制要匹配的字符数。假设介于 0 到 2 个字符之间:
select * from parts where PartNumber regexp 'ROF.{0,2}137.{0,2}7516.*'
这样,它将匹配您问题中的所有示例模式,但不会匹配 ROF 123 137XX/7516
(因为“123”和 "xx/" 超过 2 个字符)
4) Aaron Dietz 用另一种技术回答,即使用 replace() 函数。根据您的 table,这可能对您有用,但请记住,它将不再使用索引。 table 上的索引是针对列的原始值和数据类型的,但是 运行 通过 replace() 对值进行更新将意味着索引值不能用于比较。
我有一个 MySQL table,我在其中存储带有 PartNumber 字段的行,用于来自不同公司的库存数据。公司有不同的方式来传达相同的 PartNumber。
例如,假设我们有零件号 ROF-137-7516。同一部件可能具有该部件号的以下迭代:
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%';
但那只是 returns 最后一行。是否可以编写 returns 所有部分的查询?
如果您想在 SQL 中处理此问题,这是 REPLACE()
的一种方法:
SELECT *
FROM Parts
WHERE REPLACE(REPLACE(PartNumber,'-',''),' ','') LIKE REPLACE('ROF-137-7516%','-','')
这假设他们将始终输入带 -
或没有空格的 PartNumber
。
您可能希望通过几种方式来执行此操作,具体取决于您的列中的数据,以及您需要从 table 中获得什么样的性能。有关详细信息,请参阅 MySQL pattern matching 页面。
1)
根据您在 PartNumber 中期望的值,您可以将破折号替换为 %
通配符,以匹配 0 个或多个任意字符:
select * from parts where PartNumber like 'ROF%137%7516%'
但这对您来说可能还不够。例如,它会错误地 return 具有此值的行: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 之前匹配 "infinite" 个字符太多了。例如,它会错误地匹配:ROF 123 137XX/7516
。您可能已经注意到这与上面的#1 完全相同。
3.2)
如果 .*
/ %
过于宽泛,那么您可以限制 .
匹配的字符数。假设在数字之间有一个字符(space、破折号等)是标准做法,但您要考虑到用户错误(例如没有分隔字符,或键入两个分隔字符而不是一个分隔字符)。您可以使用 {0,#}
来限制要匹配的字符数。假设介于 0 到 2 个字符之间:
select * from parts where PartNumber regexp 'ROF.{0,2}137.{0,2}7516.*'
这样,它将匹配您问题中的所有示例模式,但不会匹配 ROF 123 137XX/7516
(因为“123”和 "xx/" 超过 2 个字符)
4) Aaron Dietz 用另一种技术回答,即使用 replace() 函数。根据您的 table,这可能对您有用,但请记住,它将不再使用索引。 table 上的索引是针对列的原始值和数据类型的,但是 运行 通过 replace() 对值进行更新将意味着索引值不能用于比较。