我有一个列field
的表格,其值类似于三星手机。
我的问题是如果我搜索字符串“Samsung”或“phone”,我怎么能得到这一行。如果我只将“Sam”或“ph”作为搜索词,我不想要任何结果。
我曾尝试使用ILIKE运算符但是如果我使用:
select *
from mytable
where title ILIKE 'Samsung';
它没有给出任何结果,因为它认为标题应该完全相同。此外,如果我使用title ILIKE '%Samsung%'
,那么它将适用于任何部分字符串。
简而言之,我想如果输入搜索词在我的列中作为整个单词存在,那么只给出搜索结果。
此外,如果我有多个搜索词值,那么任何词匹配都应该是结果
答案 0 :(得分:3)
您可以使用正则表达式:
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)'
请注意,这种搜索不会超快。正则表达式很昂贵,无法使用任何索引。
答案 1 :(得分:0)
您也可以使用此功能:
title ~* '(^|[^\w])samsung([^\w]|$)'
以上代码的优点是,可以很容易地扩展它以包括来自以下不同编码的字符:(土耳其语字符)
title ~* '(^|[^\wğüşıöçĞÜŞİÖÇ])samsung([^\wğüşıöçĞÜŞİÖÇ]|$)
这里是一个示例案例,您可能需要上面的扩展名。
例如在Latin5编码的数据库中,您具有'İsamsung'的值。 İ是i在土耳其语中的首都。
在这种情况下,title ~* '(\msamsung\M)'
不起作用。
此条件返回İsamsung值。因为在Latin5编码中,postgre认为İ不在字母数字范围内,因此该值与:samsung类似。
答案 2 :(得分:0)
以下解决方案已在PostgreSQL 9.6中进行了测试。
您可以使用\y
word boundary和带有交替运算符的分组构造来分隔所有可能的选择:
where title ~* '\y(?:Samsung|phone)\y'
或者,不区分大小写:
where title ~* '\y(?:Samsung|phone)\y'
请参见PostgreSQL demo。
请注意,当第一个或最后一个字符不是单词char时,\y
是不正确的方法。例如。您要搜索#samsung
或phone#
。然后,考虑使用明确的单词边界:
where title ~* '(?<!\w)(?:#samsung|phone#)(?!\w)'
在这里,如果当前位置的左侧没有(?<!\w)
字符,并且非数字,并且_
为负数,则(?!\w)
的负向后查找将失败。如果存在非数字并且当前位置的右边没有_
字符,则lookahead匹配失败。检验where
子句中是否存在匹配项的等效项是:
where title ~* '(\W|^)(?:#samsung|phone#)(\W|$)'
请参见another PostgreSQL demo online:
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|$)'