Manufacturer
==========================
id name
--------------------------
1 Company Inc.
2 Google Test.
3 3M (UNITY) USA. INC.
4 CE EE
说,我有一个字符串'Google测试。 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(绿色)” 。值中包含特殊字符,例如,.()&/
我并不是真正在寻找效率,只要它不花费50ms就能完成一次查询。
截至目前,大约有10000多个条目,但它可能会随着时间的推移而增长。
答案 0 :(得分:2)
使用LIKE
的一种方法是在开头和结尾处添加空格:
SELECT *
FROM db
WHERE ' ' || '3dad QTICE EEN ' || ' ' ILIKE '% ' || manufacturer || ' %'
如果您需要更复杂的匹配,则可能需要使用带有单词边界的正则表达式。
答案 1 :(得分:2)
要解决此问题,您确实需要使用正则表达式,因为在字符串的两边添加空格将在行的开头或结尾不匹配。通过使用正则表达式,我们也可以检查这种情况。例如:
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') || '( |$)');
答案 2 :(得分:2)
所有值均以字符或数字开头,并以数字,字符或特殊字符结尾。 ...值中包含特殊字符,例如
,.()&/
。
我建议使用正则表达式匹配运算符 ~ 。在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.起作用,因为:值以字符或数字开头
( |$)
..字符串的空格或结尾。我们需要这样的值:以数字,字符或特殊字符结尾
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 基础架构>功能: