如何在不写入所有可能的排列的情况下对多列进行查询?

Gig*_*igg 1 sql oracle

我是关于stackexchange的第一个问题,因为我在这件事上挣扎了几天:

我想在具有col1,col2,col3,col4,col5的表上进行复杂查询(PLSQL),其值为(名称:拆分 -每列一个部分)

+------+--------+--------+--------+------+
|  ID  | Col1   |  Col2  |  Col3  | Col4 |
+------+--------+--------+--------+------+
| (#1) | Andrew | Joan   | Bach   | Mike |
| (#2) | Mark   | Andrew | Livy   |      |
| (#3) | Joan   | Arch   | Donnie |      |
| (#4) | Joan   | Andrew | Lyx    |      |
+------+--------+--------+--------+------+
Run Code Online (Sandbox Code Playgroud)

名称部分的数量从1到5不等.

我想搜索不同的组合,如下所示:

  • 搜索巴赫琼迈克 - 按此顺序获得#1,#3,#4
  • 搜索Andrew Bach - 按此顺序获得以下订单#1,#2,#4

我不喜欢使用looooong查询的想法,在该查询中我将编写所有可能的排列以便为我的搜索字符串的每个部分加工

我想要达到的目的是:

  • 第一组:匹配所有n个部分(BachJoan以及Bach匹配,以任何顺序)
  • 第二组:匹配n-1个部分(我的搜索部分中至少有N-1个符合该行,按任意顺序排列)
  • 第三组:匹配n-2部分

我使用ORACLE数据库,我正在考虑在存储过程中创建它:match_my_set(query_str,col1,col2,col3,col4,col5).我会写至少5个循环(循环到循环)以实现这一点,但我怀疑这是一个专业的想法..

任何帮助表示赞赏.谢谢

Ale*_*ole 5

如果您使用11g或更高版本,则可以将列拆分为行; 这是使用CTE提供您的样本数据:

with t (id, col1, col2, col3, col4, col5) as (
  select 1, 'Andrew', 'Joan', 'Bach', 'Mike', null from dual
  union all select 2, 'Mark', 'Andrew', 'Livy', null, null from dual
  union all select 3, 'Joan', 'Arch', 'Donnie', null, null from dual
  union all select 4, 'Joan', 'Andrew', 'Lyx' , null, null from dual
)
select * from t
unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5));

        ID     COL_NO NAME 
---------- ---------- ------
         1          1 Andrew
         1          2 Joan  
         1          3 Bach  
         1          4 Mike  
         2          1 Mark  
         2          2 Andrew
         2          3 Livy  
...
Run Code Online (Sandbox Code Playgroud)

然后,您可以查找单个名称列的匹配项:

select distinct id
from (
  select * from t
  unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5))
)
where name in ('Bach', 'Joan', 'Mike')
order by id;

        ID
----------
         1
         3
         4
Run Code Online (Sandbox Code Playgroud)

你想通过计算每行中有多少项匹配来使排序更复杂.如果是这样,你可以做到:

select id, count(*) as cnt
from (
  select * from t
  unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5))
)
where name in ('Bach', 'Joan', 'Mike')
group by id;

        ID        CNT
---------- ----------
         1          3
         4          1
         3          1
Run Code Online (Sandbox Code Playgroud)

然后有另一个级别的内联视图按顺序排序,以某种方式打破关系:

select id
from (
  select id, count(*) as cnt
  from (
    select * from t
    unpivot (name for col_no in (col1 as 1, col2 as 2, col3 as 3, col4 as 4, col5 as 5))
  )
  where name in ('Bach', 'Joan', 'Mike')
  group by id
)
order by cnt desc, id;
Run Code Online (Sandbox Code Playgroud)

哪个样本数据得到的结果相同.将IN条件更改为用户('Andrew', 'Bach')也会在两个版本中获得1,2,4.

根据您获取所搜索值的方式,您可能希望使用数组(通过表集合表达式和连接),或者标记包含所有搜索词或其他变体的字符串.