![](/img/trans.png)
[英]Postgres Position function for whole phrases? String search
[英]How to search if whole word exists in a String in Postgres
我有一个带有列field
的表,该field
值类似于三星手机。
我的问题是,如果我搜索字符串“Samsung”或“phone”,如何获得这一行。 如果我只给出“Sam”或“ph”作为搜索词,我不想要任何结果。
我曾尝试使用 ILIKE 运算符,但如果我使用:
select *
from mytable
where title ILIKE 'Samsung';
它不会给出任何结果,因为它认为标题应该完全相等。 此外,如果我使用title ILIKE '%Samsung%'
那么它将适用于任何部分字符串。
简而言之,我想如果输入的搜索词作为一个完整的词存在于我的专栏中,那么只给出搜索结果。
另外,如果我有多个搜索词值,那么任何单词匹配都应该是结果
您可以为此使用正则表达式:
where title ~* '(\mphone\M)|(\msamsung\M)'
以上仅返回phone
或samsung
是完整单词的值。 正则表达式修饰符\\m
和\\M
使模式只匹配整个单词。
正则表达式运算符~*
使此不区分大小写。 上述表达式将返回Samsung Phone
或Google Phone
但不会返回Sam's House
。
如果要添加更多单词,只需使用“或”运算符添加它们即可|
where title ~* '(\mphone\M)|(\msamsung\M)|(\mbhat\M)'
请注意,这种搜索不会很快。 正则表达式很昂贵,它们不能使用任何索引。
你也可以使用这个:
title ~* '(^|[^\w])samsung([^\w]|$)'
上面一个的优点是,它可以很容易地扩展到包含来自不同编码的字符,如下所示:(土耳其字符)
title ~* '(^|[^\wğüşıöçĞÜŞİÖÇ])samsung([^\wğüşıöçĞÜŞİÖÇ]|$)
这是一个示例案例,您可能需要上述扩展。
例如; 在Latin5 编码的数据库中,您的值为'İsamsung'。 İ 在土耳其语中是 i 的首都。
在这种情况下, title ~* '(\\msamsung\\M)'
不起作用。 此条件返回 İsamsung 值。 因为在 Latin5 编码中,postgre 认为 İ 超出了字母数字范围并且该值类似于 :samsung。
以下解决方案在 PostgreSQL 9.6 中进行了测试。
您可以使用\\y
字边界和带有交替运算符的分组结构,以分隔所有可能的选择:
where title ~* '\y(?:Samsung|phone)\y'
或者,不区分大小写:
where title ~* '\y(?:Samsung|phone)\y'
请参阅PostgreSQL 演示。
请注意,当第一个或最后一个字符不是单词字符时, \\y
不是正确的方法。 例如,您想搜索#samsung
或phone#
。 然后,考虑使用明确的词边界:
where title ~* '(?<!\w)(?:#samsung|phone#)(?!\w)'
在这里, (?<!\\w)
负回顾后失败的比赛,如果有一个非alnum和无_
立即字符到左侧的当前位置,和(?!\\w)
是一个负向前查找失败的比赛如果在当前位置的右侧有一个 non-alnum 并且没有_
char。 等效于测试where
子句中是否匹配:
where title ~* '(\W|^)(?:#samsung|phone#)(\W|$)'
CREATE TABLE mmytable
(title character varying)
;
INSERT INTO mmytable
(title)
VALUES
('#Samsung Co.'),
('They have a phone#'),
('Uncle Sam phoned him')
;
select * from mmytable where title ~* '(?<!\w)(?:#samsung|phone#)(?!\w)';
此外,当您只需要在空白字符之间或字符串的开头/结尾进行匹配时,请考虑空白边界:
where title ~* '(?<!\S)(?:#samsung|phone#)(?!\S)'
where title ~* '(\s|^)(?:#samsung|phone#)(\s|$)'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.