Manufacturer
==========================
id name
--------------------------
1 Company Inc.
2 Google Test.
3 3M (UNITY) USA. INC.
4 CE EE
说,我有一个字符串'谷歌测试。 1257 SCS RANDOM 31233DD'并且我想查找表manufacturer
中的所有行,其中ht name
是给定字符串的一部分:
SELECT * FROM manufacturer
WHERE 'Google Test. 1257 SCS RANDOM 31233DD' ILIKE '%' || name || '%'
正确回报:
id name
--------------------------
2 Google Test.
但当我这样做时:
SELECT * FROM manufacturer
WHERE '3dad QTICE EEN ' ILIKE '%' || name || '%'
它返回:
id name
--------------------------
4 CE EE
我不想要像这样的部分比赛。 name
在一个单词的中间不匹配。我试过substring()
:
SELECT * from manufacturer
WHERE SUBSTRING('Google Test. 1257 SCS RANDOM 31233DD' from name) != '';
但我得到:
ERROR: invalid regular expression: quantifier operand invalid
不幸的是,由于我从外部数据库查询,我没有确切的规范。但从我所看到的,专栏是varchar(256)
。所有值均为上限,并使用普通空格。全部以字符或数字开头,以数字,字符或特殊字符结尾。例如:'CLEVLAND DRILL(GREEN)'。值中有特殊字符,例如,.()&/
我不是在寻找效率,只要它不需要超过50毫秒来进行一次查询。
截至目前,大约有10000多个条目,但它可以随着时间的推移而增长。
使用LIKE
的一种方法是在开头和结尾添加空格:
SELECT *
FROM db
WHERE ' ' || '3dad QTICE EEN ' || ' ' ILIKE '% ' || manufacturer || ' %'
如果您需要更复杂的匹配,那么您可能需要使用带有字边界的正则表达式。
所有值都以字符或数字开头,以数字,字符或特殊字符结尾。 ...值中有特殊字符,例如
,.()&/
。
我建议正则表达式匹配运算符~。在name
中仔细定义边界并转义特殊字符:
创建一次:
CREATE OR REPLACE FUNCTION f_regexp_escape(text)
RETURNS text AS
$func$
SELECT regexp_replace($1, '([!$()*+.:<=>?[\\\]^{|}-])', '\\\1', 'g')
$func$ LANGUAGE sql IMMUTABLE;
然后:
SELECT * FROM manufacturer
WHERE '3dad QTICE EEN ' ~ ('\m' || f_regexp_escape(name) || '( |$)')
\m
.. beginning of a word. Works,因为:值以字符或数字开头
( |$)
..一个空格或字符串的结尾。我们需要这个值,因为值:以数字,字符或特殊字符结尾
manufacturer.name
的内容是该模式的核心。你想要它的所有字符的字面含义,所以通过适当地转义去除任何特殊含义。 LIKE
(少数特殊字符)以及正则表达式匹配运算符~
(更多特殊字符)都是如此。经常被忽视而且非常陷入困境。这让你(和界限的棘手定义)。读这个!
然后使用函数f_regexp_escape()
进行演示。像name
一样:
3M (UNITY) USA. INC.
变为:
3M \(UNITY\) USA\. INC\.
可能很方便存储表manufacturer
中容易逃脱的模式,也许作为附加列。也许添加这样的填充:
\m3M \(UNITY\) USA\. INC\.( |$)
或者如同演示一样动态生成模式。
这样,name
可以是单个单词或整个短语,并以任何字符结尾。但是开始和结束永远不会在另一边的“单词”中间匹配。
Postgres中有一系列其他模式匹配工具:
如果您的表很大,请考虑使用优化索引和短语搜索功能的full text search基础架构:
要解决此问题,您确实需要使用正则表达式,因为在行的开头或结尾处添加字符串两侧的空格将不匹配。通过使用正则表达式,我们也可以检查这种情况。例如:
SELECT *
FROM manufacturer
WHERE 'Google Test. 1257 36700 SCS RANDOM WORD 31233DD' ~ ('(^| )' || name || '( |$)');
输出:
id name
2 Google Test.
查询:
SELECT *
FROM manufacturer
WHERE '3dad QTICE EEN ' ~ ('(^| )' || name || '( |$)');
输出:
There are no results to be displayed.
查询:
SELECT *
FROM manufacturer
WHERE 'CE EE ' ~ ('(^| )' || name || '( |$)');
输出:
id name
4 CE EE
更新
因为表中的name
值可以包含在正则表达式中具有特殊含义的字符,所以在将名称包含在正则表达式中之前,需要对它们进行转义。你可以用REGEXP_REPLACE
这样做,例如
REGEXP_REPLACE(name, '([\\.+*?[^\]$(){}=!<>|:\-#])', '\\\1', 'g')
所以你的查询应该是:
SELECT *
FROM manufacturer
WHERE 'Google Test. 1257 36700 SCS RANDOM WORD 31233DD' ~ ('(^| )' || REGEXP_REPLACE(name, '([\\.+*?[^\]$(){}=!<>|:\-#])', '\\\1', 'g') || '( |$)');