在多个值上,所有值都必须匹配

zzzyeukh  于 2021-07-26  发布在  Java
关注(0)|答案(4)|浏览(255)

我正在使用like查询旧的oracle数据库以匹配名称。如果一个多词模式(可以是1个词,3个词,8个词,随便什么)可以独立于词序与名字进行匹配就好了。例如,如果用户搜索 "rob jon" ,会匹配的

ROBERT JONES
JONATHON ADAM PROBE

但不匹配

ROB SMITH
PETER JONES

如果要求是“至少有一个单词应该匹配”,我可以使用 REGEXP_LIKE(name, 'rob|jon", 'i') . 但我不知道如何使它匹配,只有当所有的字都在某个地方找到的名字。我可以用oracle文本来做这个,但是我不能在这个数据库中使用它。我也不能轻松地将单词存储在一个表中以连接到其中任何一个。
查询当前是静态的,并且使用绑定变量,因此我不希望为搜索模式中的每个单词添加额外的like predicate 。
有什么想法吗?

dsekswqp

dsekswqp1#

根据你的问题和帖子里的数据,我用了这个表格

create table name_pattern 
(
    name_1 varchar(200)
);

插入语句:

insert into name_pattern 
select ( 'ROBERT JONES') from dual union all 
select ('JONATHON ADAM PROBE') from dual union all
select  ('ROB SMITH') from dual union all
select  ('PETER JONES') from dual;
commit;

如果你分别搜索“rob”和“jon”,那么试试这个方法。

select name from table_name where lower(name) like '%rob%' and lower(name) like '%jon%' ;

如果你想搜索“rob jon”并得到你想要的结果,试试这个

select * from name_pattern where REGEXP_COUNT(name_1, 'rob|jon',1, 'i') =2;
amrnrhlw

amrnrhlw2#

您希望您的查询接受一个bind变量,该变量包含名称部分的空白分隔列表,例如“rob jon”。
您可以编写一个递归查询,从该字符串中获取单个名称部分。然后使用 NOT EXISTS 只保留不存在任何不匹配的名称。

with parameters as
(
  select :namepartlist as namepartlist from dual
)
, nameparts (namepart, namepartlist, occurrence) as
(
  select regexp_substr(namepartlist, '[^ ]+', 1, 1), namepartlist, 1
  from parameters
  union all
  select regexp_substr(namepartlist, '[^ ]+', 1, occurrence + 1), namepartlist, occurrence + 1
  from nameparts
  where regexp_substr(namepartlist, '[^ ]+', 1, occurrence + 1) is not null
)
select * 
from mytable
where not exists
(
  select null
  from nameparts
  where lower(mytable.name) not like '%' || lower(nameparts.namepart) || '%'
)
order by name;

你可以替换

where lower(mytable.name) not like '%' || lower(nameparts.namepart) || '%'

通过

where not regexp_like(mytable.name, nameparts.namepart, 'i')

如果你更喜欢的话。
演示:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=5e48caaa20e9397afe65516504c62acd

fnvucqvd

fnvucqvd3#

如果不希望为搜索模式中的每个单词添加额外的like predicate (最好的解决方案imho),可以创建pl/sql函数来进行匹配

FUNCTION PATTERN_MATCHES(pattern in varchar2, name in varchar2) returns number
is
Begin *pseudocode*
  *convert pattern to lowercase*
  *split pattern by spaces*
  *for each part, Loop*
     if NOT lower(name) like %part% then 
        return 0; --early exit
     end;
  End Loop;
  return 1; --all parts have a match
end;

select * from employee where PATTERN_MATCHES(:pattern, name)=1

然后就可以有一个静态参数化查询。好的一面是,您可以在不接触前端应用程序的情况下扩展行为(例如添加高级搜索)。
ps:函数代码是特意留给你写的。问问你是否需要帮助。
ps2:返回“number”而不是布尔值将有助于使用遗留数据库驱动程序。如果你觉得合适的话,可以随意使用整数或布尔值。

deyfvvtc

deyfvvtc4#

建立在@jfrd解决方案上的无耻。。。这有什么好处吗(在大table上的表现将令人震惊)。
基本上,用“%”替换所有空格(此处不适用于连续空格)。

var search_text varchar2(30)

exec :search_text := 'Rob Jon';

select name
from table_name
where lower(name) like REPLACE('%' || :search_text || '%', ' ', '%' ) ;

相关问题