Oracle 从多个数据库表中查找字符串匹配

Oracle Finding a string match from multiple database tables

这个问题描述起来有点复杂,但我会尝试用一个例子来解释它。我以为我可以使用 Oracle Instr 函数来完成此操作,但它不接受查询作为参数。

这里是我的数据的简化:

  Table1
   Person         Qualities
   Joe            5,6,7,8,9
   Mary           7,8,10,15,20
   Bob            7,8,9,10,11,12

   Table2
   Id             Desc
   5              Nice
   6              Tall
   7              Short

   Table3
   Id             Desc
   8              Angry
   9              Sad
   10             Fun

   Table4
   Id             Desc
   11             Boring    
   12             Happy
   15             Cool
   20             Mad

这里有一些查询可以让您了解我要完成的任务:

   select * from table1 
   where instr (Qualities, select Id from table2, 1,1) <> 0
   and instr (Qualities, select Id from table3, 1,1) <> 0 
   and instr (Qualities, select Id from table3, 1,1) <> 0

我试图找出哪些人至少具有 3 组品质(表 2、3 和 4)中的每一种品质

所以 Joe 不会在结果中返回,因为他不具备 3 个组中每个组的质量,但 Mary 和 Joe 会返回,因为他们每个组至少有 1 个质量。

我们是 运行 Oracle 12,谢谢!

这是一种选择:

SQL> with
  2  table1 (person, qualities) as
  3    (select 'Joe', '5,6,7,8,9' from dual union all
  4     select 'Mary', '7,8,10,15,20' from dual union all
  5     select 'Bob', '7,8,9,10,11,12' from dual
  6    ),
  7  table2 (id, descr) as
  8    (select 5, 'Nice' from dual union all
  9     select 6, 'Tall' from dual union all
 10     select 7, 'Short' from dual
 11    ),
 12  table3 (id, descr) as
 13    (select 8, 'Angry' from dual union all
 14     select 9, 'Sad' from dual union all
 15     select 10, 'Fun' from dual
 16    ),
 17  table4 (id, descr) as
 18    (select 11, 'Boring' from dual union all
 19     select 12, 'Happy' from dual union all
 20     select 15, 'Cool' from dual union all
 21     select 20, 'Mad' from dual
 22    ),
 23  t1new (person, id) as
 24    (select person, regexp_substr(qualities, '[^,]+', 1, column_value) id
 25     from table1 cross join table(cast(multiset(select level from dual
 26                                                connect by level <= regexp_count(qualities, ',') + 1
 27                                               ) as sys.odcinumberlist))
 28    )
 29  select a.person,
 30        count(b.id) bid,
 31        count(c.id) cid,
 32        count(d.id) did
 33  from t1new a left join table2 b on a.id = b.id
 34               left join table3 c on a.id = c.id
 35               left join table4 d on a.id = d.id
 36  group by a.person
 37  having (    count(b.id) > 0
 38          and count(c.id) > 0
 39          and count(d.id) > 0
 40         );

PERS        BID        CID        DID
---- ---------- ---------- ----------
Bob           1          3          2
Mary          1          2          2

SQL>

它有什么作用?

  • 第 1 - 22 行代表您的样本数据
  • T1NEW CTE(第 23 - 28 行)将每个人的逗号分隔质量分成几行
  • final select(第 29 - 40 行)是外部连接 t1new 与每个 "description" 表(table2/3/4)并计算其中包含多少质量每个人的品质(由 t1new 中的行表示)
  • having 子句是这里 return 只需要的人;这些计数中的每一个都必须是正数

也许这会有所帮助: {1} 创建一个对所有质量进行分类并允许您 SELECT 质量 ID 和类别的视图。 {2} 将视图联接到 TABLE1 并使用 "splits" 存储在 TABLE1 中的 CSV 值的联接条件。

{1} 查看

create or replace view allqualities
as
select 1 as category, id as qid, descr from table2
union
select 2, id, descr from table3
union
select 3, id, descr from table4
;

select * from allqualities order by category, qid ;

  CATEGORY        QID DESCR 
---------- ---------- ------
         1          5 Nice  
         1          6 Tall  
         1          7 Short 
         2          8 Angry 
         2          9 Sad   
         2         10 Fun   
         3         11 Boring
         3         12 Happy 
         3         15 Cool  
         3         20 Mad 

{2}查询

--  JOIN CONDITION:
--  {1} add a comma at the start and at the end of T1.qualities
--  {2} remove all blanks (spaces) from T1.qualities
--  {3} use LIKE and the qid (of allqualities), wrapped in commas
--
--  inline view: use UNIQUE, otherwise we may get counts > 3
--

select person
from (
  select unique person, category
  from table1 T1 
    join allqualities A 
      on ',' || replace( T1.qualities, ' ', '' ) || ',' like '%,' || A.qid || ',%'
)
group by person
having count(*) = ( select count( distinct category ) from allqualities )
;

-- result
PERSON   
Bob      
Mary 

使用 Oracle 18c 和 11g 进行了测试。 DBfiddle here.